cubefs

Форк
0
482 строки · 12.2 Кб
1
// Copyright 2019 The Prometheus Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
//go:build linux
15
// +build linux
16

17
package procfs
18

19
import (
20
	"bufio"
21
	"bytes"
22
	"errors"
23
	"fmt"
24
	"regexp"
25
	"strconv"
26
	"strings"
27

28
	"github.com/prometheus/procfs/internal/util"
29
)
30

31
// CPUInfo contains general information about a system CPU found in /proc/cpuinfo.
32
type CPUInfo struct {
33
	Processor       uint
34
	VendorID        string
35
	CPUFamily       string
36
	Model           string
37
	ModelName       string
38
	Stepping        string
39
	Microcode       string
40
	CPUMHz          float64
41
	CacheSize       string
42
	PhysicalID      string
43
	Siblings        uint
44
	CoreID          string
45
	CPUCores        uint
46
	APICID          string
47
	InitialAPICID   string
48
	FPU             string
49
	FPUException    string
50
	CPUIDLevel      uint
51
	WP              string
52
	Flags           []string
53
	Bugs            []string
54
	BogoMips        float64
55
	CLFlushSize     uint
56
	CacheAlignment  uint
57
	AddressSizes    string
58
	PowerManagement string
59
}
60

61
var (
62
	cpuinfoClockRegexp          = regexp.MustCompile(`([\d.]+)`)
63
	cpuinfoS390XProcessorRegexp = regexp.MustCompile(`^processor\s+(\d+):.*`)
64
)
65

66
// CPUInfo returns information about current system CPUs.
67
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
68
func (fs FS) CPUInfo() ([]CPUInfo, error) {
69
	data, err := util.ReadFileNoStat(fs.proc.Path("cpuinfo"))
70
	if err != nil {
71
		return nil, err
72
	}
73
	return parseCPUInfo(data)
74
}
75

76
func parseCPUInfoX86(info []byte) ([]CPUInfo, error) {
77
	scanner := bufio.NewScanner(bytes.NewReader(info))
78

79
	// find the first "processor" line
80
	firstLine := firstNonEmptyLine(scanner)
81
	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
82
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
83
	}
84
	field := strings.SplitN(firstLine, ": ", 2)
85
	v, err := strconv.ParseUint(field[1], 0, 32)
86
	if err != nil {
87
		return nil, err
88
	}
89
	firstcpu := CPUInfo{Processor: uint(v)}
90
	cpuinfo := []CPUInfo{firstcpu}
91
	i := 0
92

93
	for scanner.Scan() {
94
		line := scanner.Text()
95
		if !strings.Contains(line, ":") {
96
			continue
97
		}
98
		field := strings.SplitN(line, ": ", 2)
99
		switch strings.TrimSpace(field[0]) {
100
		case "processor":
101
			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
102
			i++
103
			v, err := strconv.ParseUint(field[1], 0, 32)
104
			if err != nil {
105
				return nil, err
106
			}
107
			cpuinfo[i].Processor = uint(v)
108
		case "vendor", "vendor_id":
109
			cpuinfo[i].VendorID = field[1]
110
		case "cpu family":
111
			cpuinfo[i].CPUFamily = field[1]
112
		case "model":
113
			cpuinfo[i].Model = field[1]
114
		case "model name":
115
			cpuinfo[i].ModelName = field[1]
116
		case "stepping":
117
			cpuinfo[i].Stepping = field[1]
118
		case "microcode":
119
			cpuinfo[i].Microcode = field[1]
120
		case "cpu MHz":
121
			v, err := strconv.ParseFloat(field[1], 64)
122
			if err != nil {
123
				return nil, err
124
			}
125
			cpuinfo[i].CPUMHz = v
126
		case "cache size":
127
			cpuinfo[i].CacheSize = field[1]
128
		case "physical id":
129
			cpuinfo[i].PhysicalID = field[1]
130
		case "siblings":
131
			v, err := strconv.ParseUint(field[1], 0, 32)
132
			if err != nil {
133
				return nil, err
134
			}
135
			cpuinfo[i].Siblings = uint(v)
136
		case "core id":
137
			cpuinfo[i].CoreID = field[1]
138
		case "cpu cores":
139
			v, err := strconv.ParseUint(field[1], 0, 32)
140
			if err != nil {
141
				return nil, err
142
			}
143
			cpuinfo[i].CPUCores = uint(v)
144
		case "apicid":
145
			cpuinfo[i].APICID = field[1]
146
		case "initial apicid":
147
			cpuinfo[i].InitialAPICID = field[1]
148
		case "fpu":
149
			cpuinfo[i].FPU = field[1]
150
		case "fpu_exception":
151
			cpuinfo[i].FPUException = field[1]
152
		case "cpuid level":
153
			v, err := strconv.ParseUint(field[1], 0, 32)
154
			if err != nil {
155
				return nil, err
156
			}
157
			cpuinfo[i].CPUIDLevel = uint(v)
158
		case "wp":
159
			cpuinfo[i].WP = field[1]
160
		case "flags":
161
			cpuinfo[i].Flags = strings.Fields(field[1])
162
		case "bugs":
163
			cpuinfo[i].Bugs = strings.Fields(field[1])
164
		case "bogomips":
165
			v, err := strconv.ParseFloat(field[1], 64)
166
			if err != nil {
167
				return nil, err
168
			}
169
			cpuinfo[i].BogoMips = v
170
		case "clflush size":
171
			v, err := strconv.ParseUint(field[1], 0, 32)
172
			if err != nil {
173
				return nil, err
174
			}
175
			cpuinfo[i].CLFlushSize = uint(v)
176
		case "cache_alignment":
177
			v, err := strconv.ParseUint(field[1], 0, 32)
178
			if err != nil {
179
				return nil, err
180
			}
181
			cpuinfo[i].CacheAlignment = uint(v)
182
		case "address sizes":
183
			cpuinfo[i].AddressSizes = field[1]
184
		case "power management":
185
			cpuinfo[i].PowerManagement = field[1]
186
		}
187
	}
188
	return cpuinfo, nil
189
}
190

191
func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
192
	scanner := bufio.NewScanner(bytes.NewReader(info))
193

194
	firstLine := firstNonEmptyLine(scanner)
195
	match, _ := regexp.MatchString("^[Pp]rocessor", firstLine)
196
	if !match || !strings.Contains(firstLine, ":") {
197
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
198
	}
199
	field := strings.SplitN(firstLine, ": ", 2)
200
	cpuinfo := []CPUInfo{}
201
	featuresLine := ""
202
	commonCPUInfo := CPUInfo{}
203
	i := 0
204
	if strings.TrimSpace(field[0]) == "Processor" {
205
		commonCPUInfo = CPUInfo{ModelName: field[1]}
206
		i = -1
207
	} else {
208
		v, err := strconv.ParseUint(field[1], 0, 32)
209
		if err != nil {
210
			return nil, err
211
		}
212
		firstcpu := CPUInfo{Processor: uint(v)}
213
		cpuinfo = []CPUInfo{firstcpu}
214
	}
215

216
	for scanner.Scan() {
217
		line := scanner.Text()
218
		if !strings.Contains(line, ":") {
219
			continue
220
		}
221
		field := strings.SplitN(line, ": ", 2)
222
		switch strings.TrimSpace(field[0]) {
223
		case "processor":
224
			cpuinfo = append(cpuinfo, commonCPUInfo) // start of the next processor
225
			i++
226
			v, err := strconv.ParseUint(field[1], 0, 32)
227
			if err != nil {
228
				return nil, err
229
			}
230
			cpuinfo[i].Processor = uint(v)
231
		case "BogoMIPS":
232
			if i == -1 {
233
				cpuinfo = append(cpuinfo, commonCPUInfo) // There is only one processor
234
				i++
235
				cpuinfo[i].Processor = 0
236
			}
237
			v, err := strconv.ParseFloat(field[1], 64)
238
			if err != nil {
239
				return nil, err
240
			}
241
			cpuinfo[i].BogoMips = v
242
		case "Features":
243
			featuresLine = line
244
		case "model name":
245
			cpuinfo[i].ModelName = field[1]
246
		}
247
	}
248
	fields := strings.SplitN(featuresLine, ": ", 2)
249
	for i := range cpuinfo {
250
		cpuinfo[i].Flags = strings.Fields(fields[1])
251
	}
252
	return cpuinfo, nil
253

254
}
255

256
func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
257
	scanner := bufio.NewScanner(bytes.NewReader(info))
258

259
	firstLine := firstNonEmptyLine(scanner)
260
	if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") {
261
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
262
	}
263
	field := strings.SplitN(firstLine, ": ", 2)
264
	cpuinfo := []CPUInfo{}
265
	commonCPUInfo := CPUInfo{VendorID: field[1]}
266

267
	for scanner.Scan() {
268
		line := scanner.Text()
269
		if !strings.Contains(line, ":") {
270
			continue
271
		}
272
		field := strings.SplitN(line, ": ", 2)
273
		switch strings.TrimSpace(field[0]) {
274
		case "bogomips per cpu":
275
			v, err := strconv.ParseFloat(field[1], 64)
276
			if err != nil {
277
				return nil, err
278
			}
279
			commonCPUInfo.BogoMips = v
280
		case "features":
281
			commonCPUInfo.Flags = strings.Fields(field[1])
282
		}
283
		if strings.HasPrefix(line, "processor") {
284
			match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line)
285
			if len(match) < 2 {
286
				return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
287
			}
288
			cpu := commonCPUInfo
289
			v, err := strconv.ParseUint(match[1], 0, 32)
290
			if err != nil {
291
				return nil, err
292
			}
293
			cpu.Processor = uint(v)
294
			cpuinfo = append(cpuinfo, cpu)
295
		}
296
		if strings.HasPrefix(line, "cpu number") {
297
			break
298
		}
299
	}
300

301
	i := 0
302
	for scanner.Scan() {
303
		line := scanner.Text()
304
		if !strings.Contains(line, ":") {
305
			continue
306
		}
307
		field := strings.SplitN(line, ": ", 2)
308
		switch strings.TrimSpace(field[0]) {
309
		case "cpu number":
310
			i++
311
		case "cpu MHz dynamic":
312
			clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
313
			v, err := strconv.ParseFloat(clock, 64)
314
			if err != nil {
315
				return nil, err
316
			}
317
			cpuinfo[i].CPUMHz = v
318
		case "physical id":
319
			cpuinfo[i].PhysicalID = field[1]
320
		case "core id":
321
			cpuinfo[i].CoreID = field[1]
322
		case "cpu cores":
323
			v, err := strconv.ParseUint(field[1], 0, 32)
324
			if err != nil {
325
				return nil, err
326
			}
327
			cpuinfo[i].CPUCores = uint(v)
328
		case "siblings":
329
			v, err := strconv.ParseUint(field[1], 0, 32)
330
			if err != nil {
331
				return nil, err
332
			}
333
			cpuinfo[i].Siblings = uint(v)
334
		}
335
	}
336

337
	return cpuinfo, nil
338
}
339

340
func parseCPUInfoMips(info []byte) ([]CPUInfo, error) {
341
	scanner := bufio.NewScanner(bytes.NewReader(info))
342

343
	// find the first "processor" line
344
	firstLine := firstNonEmptyLine(scanner)
345
	if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") {
346
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
347
	}
348
	field := strings.SplitN(firstLine, ": ", 2)
349
	cpuinfo := []CPUInfo{}
350
	systemType := field[1]
351

352
	i := 0
353

354
	for scanner.Scan() {
355
		line := scanner.Text()
356
		if !strings.Contains(line, ":") {
357
			continue
358
		}
359
		field := strings.SplitN(line, ": ", 2)
360
		switch strings.TrimSpace(field[0]) {
361
		case "processor":
362
			v, err := strconv.ParseUint(field[1], 0, 32)
363
			if err != nil {
364
				return nil, err
365
			}
366
			i = int(v)
367
			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
368
			cpuinfo[i].Processor = uint(v)
369
			cpuinfo[i].VendorID = systemType
370
		case "cpu model":
371
			cpuinfo[i].ModelName = field[1]
372
		case "BogoMIPS":
373
			v, err := strconv.ParseFloat(field[1], 64)
374
			if err != nil {
375
				return nil, err
376
			}
377
			cpuinfo[i].BogoMips = v
378
		}
379
	}
380
	return cpuinfo, nil
381
}
382

383
func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) {
384
	scanner := bufio.NewScanner(bytes.NewReader(info))
385

386
	firstLine := firstNonEmptyLine(scanner)
387
	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
388
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
389
	}
390
	field := strings.SplitN(firstLine, ": ", 2)
391
	v, err := strconv.ParseUint(field[1], 0, 32)
392
	if err != nil {
393
		return nil, err
394
	}
395
	firstcpu := CPUInfo{Processor: uint(v)}
396
	cpuinfo := []CPUInfo{firstcpu}
397
	i := 0
398

399
	for scanner.Scan() {
400
		line := scanner.Text()
401
		if !strings.Contains(line, ":") {
402
			continue
403
		}
404
		field := strings.SplitN(line, ": ", 2)
405
		switch strings.TrimSpace(field[0]) {
406
		case "processor":
407
			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
408
			i++
409
			v, err := strconv.ParseUint(field[1], 0, 32)
410
			if err != nil {
411
				return nil, err
412
			}
413
			cpuinfo[i].Processor = uint(v)
414
		case "cpu":
415
			cpuinfo[i].VendorID = field[1]
416
		case "clock":
417
			clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
418
			v, err := strconv.ParseFloat(clock, 64)
419
			if err != nil {
420
				return nil, err
421
			}
422
			cpuinfo[i].CPUMHz = v
423
		}
424
	}
425
	return cpuinfo, nil
426
}
427

428
func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
429
	scanner := bufio.NewScanner(bytes.NewReader(info))
430

431
	firstLine := firstNonEmptyLine(scanner)
432
	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
433
		return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
434
	}
435
	field := strings.SplitN(firstLine, ": ", 2)
436
	v, err := strconv.ParseUint(field[1], 0, 32)
437
	if err != nil {
438
		return nil, err
439
	}
440
	firstcpu := CPUInfo{Processor: uint(v)}
441
	cpuinfo := []CPUInfo{firstcpu}
442
	i := 0
443

444
	for scanner.Scan() {
445
		line := scanner.Text()
446
		if !strings.Contains(line, ":") {
447
			continue
448
		}
449
		field := strings.SplitN(line, ": ", 2)
450
		switch strings.TrimSpace(field[0]) {
451
		case "processor":
452
			v, err := strconv.ParseUint(field[1], 0, 32)
453
			if err != nil {
454
				return nil, err
455
			}
456
			i = int(v)
457
			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
458
			cpuinfo[i].Processor = uint(v)
459
		case "hart":
460
			cpuinfo[i].CoreID = field[1]
461
		case "isa":
462
			cpuinfo[i].ModelName = field[1]
463
		}
464
	}
465
	return cpuinfo, nil
466
}
467

468
func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode
469
	return nil, errors.New("not implemented")
470
}
471

472
// firstNonEmptyLine advances the scanner to the first non-empty line
473
// and returns the contents of that line.
474
func firstNonEmptyLine(scanner *bufio.Scanner) string {
475
	for scanner.Scan() {
476
		line := scanner.Text()
477
		if strings.TrimSpace(line) != "" {
478
			return line
479
		}
480
	}
481
	return ""
482
}
483

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.