@cryptotaxi247 / netdata-1 / commits / 3acc67a1c

add intel_gpu_top collector (#17344)

Ilya Mashchenko committed Apr 9, 2024 at 13:45 UTC 3acc67a1c7dea77a7e2160c705ef00ab0294cb0d
15 files changed +887
src/go/collectors/go.d.plugin/README.md
+1
@@ -77,6 +77,7 @@ see the appropriate collector readme.
77 | [haproxy](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/haproxy) | HAProxy |
78 | [hdfs](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/hdfs) | HDFS |
79 | [httpcheck](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/httpcheck) | Any HTTP Endpoint |
80 +| [intelgpu](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/intelgpu) | Intel integrated GPU |
81 | [isc_dhcpd](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/isc_dhcpd) | ISC DHCP |
82 | [k8s_kubelet](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/k8s_kubelet) | Kubelet |
83 | [k8s_kubeproxy](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/k8s_kubeproxy) | Kube-proxy |
src/go/collectors/go.d.plugin/config/go.d.conf
+1
@@ -40,6 +40,7 @@ modules:
40 # haproxy: yes
41 # hdfs: yes
42 # httpcheck: yes
43 +# intelgpu: yes
44 # isc_dhcpd: yes
45 # k8s_kubelet: yes
46 # k8s_kubeproxy: yes
src/go/collectors/go.d.plugin/config/go.d/intelgpu.conf new
+6
@@ -0,0 +1,6 @@
1 +## All available configuration options, their descriptions and default values:
2 +## https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/intelgpu#readme
3 +
4 +#jobs:
5 +# - name: intelgpu
6 +# binary_path: /usr/bin/intel_gpu_top
src/go/collectors/go.d.plugin/modules/init.go
+1
@@ -30,6 +30,7 @@ import (
30 _ "github.com/netdata/netdata/go/go.d.plugin/modules/haproxy"
31 _ "github.com/netdata/netdata/go/go.d.plugin/modules/hdfs"
32 _ "github.com/netdata/netdata/go/go.d.plugin/modules/httpcheck"
33 + _ "github.com/netdata/netdata/go/go.d.plugin/modules/intelgpu"
34 _ "github.com/netdata/netdata/go/go.d.plugin/modules/isc_dhcpd"
35 _ "github.com/netdata/netdata/go/go.d.plugin/modules/k8s_kubelet"
36 _ "github.com/netdata/netdata/go/go.d.plugin/modules/k8s_kubeproxy"
src/go/collectors/go.d.plugin/modules/intelgpu/charts.go new
+92
@@ -0,0 +1,92 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + "fmt"
7 + "strings"
8 +
9 + "github.com/netdata/netdata/go/go.d.plugin/agent/module"
10 +)
11 +
12 +const (
13 + prioGPUFrequency = module.Priority + iota
14 + prioGPUPower
15 + prioGPUEngineBusy
16 +)
17 +
18 +var charts = module.Charts{
19 + intelGPUFrequencyChart.Copy(),
20 + intelGPUPowerGPUChart.Copy(),
21 +}
22 +
23 +var intelGPUFrequencyChart = module.Chart{
24 + ID: "igpu_frequency",
25 + Title: "Intel GPU frequency",
26 + Units: "MHz",
27 + Fam: "frequency",
28 + Ctx: "intelgpu.frequency",
29 + Type: module.Line,
30 + Priority: prioGPUFrequency,
31 + Dims: module.Dims{
32 + {ID: "frequency_actual", Name: "frequency", Div: precision},
33 + },
34 +}
35 +
36 +var intelGPUPowerGPUChart = module.Chart{
37 + ID: "igpu_power_gpu",
38 + Title: "Intel GPU power",
39 + Units: "Watts",
40 + Fam: "power",
41 + Ctx: "intelgpu.power",
42 + Type: module.Line,
43 + Priority: prioGPUPower,
44 + Dims: module.Dims{
45 + {ID: "power_gpu", Name: "gpu", Div: precision},
46 + {ID: "power_package", Name: "package", Div: precision},
47 + },
48 +}
49 +
50 +var intelGPUEngineBusyPercChartTmpl = module.Chart{
51 + ID: "igpu_engine_%s_busy_percentage",
52 + Title: "Intel GPU engine busy time percentage",
53 + Units: "percentage",
54 + Fam: "engines",
55 + Ctx: "intelgpu.engine_busy_perc",
56 + Type: module.Line,
57 + Priority: prioGPUEngineBusy,
58 + Dims: module.Dims{
59 + {ID: "engine_%s_busy", Name: "busy", Div: precision},
60 + },
61 +}
62 +
63 +func (ig *IntelGPU) addEngineCharts(engine string) {
64 + chart := intelGPUEngineBusyPercChartTmpl.Copy()
65 +
66 + s := strings.ToLower(engine)
67 + s = strings.ReplaceAll(s, "/", "_")
68 +
69 + chart.ID = fmt.Sprintf(chart.ID, s)
70 + chart.Labels = []module.Label{
71 + {Key: "engine", Value: engineDisplayName(engine)},
72 + {Key: "engine_instance", Value: engine},
73 + }
74 + for _, dim := range chart.Dims {
75 + dim.ID = fmt.Sprintf(dim.ID, engine)
76 + }
77 +
78 + if err := ig.Charts().Add(chart); err != nil {
79 + ig.Warning(err)
80 + }
81 +}
82 +
83 +func engineDisplayName(engine string) string {
84 + // https://gitlab.freedesktop.org/drm/igt-gpu-tools/-/blob/master/tools/intel_gpu_top.c#L431
85 + engines := []string{"Render/3D", "Blitter", "VideoEnhance", "Video", "Compute"}
86 + for _, name := range engines {
87 + if strings.HasPrefix(engine, name) {
88 + return name
89 + }
90 + }
91 + return "unknown"
92 +}
src/go/collectors/go.d.plugin/modules/intelgpu/collect.go new
+76
@@ -0,0 +1,76 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + "encoding/json"
7 + "errors"
8 + "fmt"
9 +)
10 +
11 +type (
12 + gpuSummaryStats struct {
13 + Frequency struct {
14 + Actual float64 `json:"actual"`
15 + } `json:"frequency"`
16 + Power struct {
17 + GPU float64 `json:"gpu"`
18 + Package float64 `json:"package"`
19 + } `json:"power"`
20 + Engines map[string]struct {
21 + Busy float64 `json:"busy"`
22 + } `json:"engines"`
23 + }
24 +)
25 +
26 +const precision = 100
27 +
28 +func (ig *IntelGPU) collect() (map[string]int64, error) {
29 + if ig.exec == nil {
30 + return nil, errors.New("collector not initialized")
31 + }
32 +
33 + stats, err := ig.getGPUSummaryStats()
34 + if err != nil {
35 + return nil, err
36 + }
37 +
38 + mx := make(map[string]int64)
39 +
40 + mx["frequency_actual"] = int64(stats.Frequency.Actual * precision)
41 + mx["power_gpu"] = int64(stats.Power.GPU * precision)
42 + mx["power_package"] = int64(stats.Power.Package * precision)
43 +
44 + for name, es := range stats.Engines {
45 + if !ig.engines[name] {
46 + ig.addEngineCharts(name)
47 + ig.engines[name] = true
48 + }
49 +
50 + key := fmt.Sprintf("engine_%s_busy", name)
51 + mx[key] = int64(es.Busy * precision)
52 + }
53 +
54 + return mx, nil
55 +}
56 +func (ig *IntelGPU) getGPUSummaryStats() (*gpuSummaryStats, error) {
57 + bs, err := ig.exec.queryGPUSummaryJson()
58 + if err != nil {
59 + return nil, err
60 + }
61 +
62 + if len(bs) == 0 {
63 + return nil, errors.New("query returned empty response")
64 + }
65 +
66 + var stats gpuSummaryStats
67 + if err := json.Unmarshal(bs, &stats); err != nil {
68 + return nil, err
69 + }
70 +
71 + if len(stats.Engines) == 0 {
72 + return nil, errors.New("query returned unexpected response")
73 + }
74 +
75 + return &stats, nil
76 +}
src/go/collectors/go.d.plugin/modules/intelgpu/config_schema.json new
+37
@@ -0,0 +1,37 @@
1 +{
2 + "jsonSchema": {
3 + "$schema": "http://json-schema.org/draft-07/schema#",
4 + "title": "Intel GPU collector configuration.",
5 + "type": "object",
6 + "properties": {
7 + "update_every": {
8 + "title": "Update every",
9 + "description": "Data collection interval, measured in seconds.",
10 + "type": "integer",
11 + "minimum": 1,
12 + "default": 1
13 + },
14 + "binary_path": {
15 + "title": "Binary path",
16 + "description": "Path to the `intel_gpu_top` binary.",
17 + "type": "string",
18 + "default": "/usr/bin/intel_gpu_top"
19 + }
20 + },
21 + "required": [
22 + "binary_path"
23 + ],
24 + "additionalProperties": false,
25 + "patternProperties": {
26 + "^name$": {}
27 + }
28 + },
29 + "uiSchema": {
30 + "uiOptions": {
31 + "fullPage": true
32 + },
33 + "binary_path": {
34 + "ui:help": "If an absolute path is provided, the collector will use it directly; otherwise, it will search for the binary in directories specified in the PATH environment variable."
35 + }
36 + }
37 +}
src/go/collectors/go.d.plugin/modules/intelgpu/exec.go new
+140
@@ -0,0 +1,140 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + "bufio"
7 + "bytes"
8 + "errors"
9 + "os/exec"
10 + "strconv"
11 + "sync"
12 + "time"
13 +)
14 +
15 +func newIntelGpuTopExec(binPath string, updateEvery int) (*intelGpuTopExec, error) {
16 + topExec := &intelGpuTopExec{
17 + binPath: binPath,
18 + updateEvery: updateEvery,
19 + }
20 +
21 + if err := topExec.run(); err != nil {
22 + return nil, err
23 + }
24 +
25 + return topExec, nil
26 +}
27 +
28 +type intelGpuTopExec struct {
29 + binPath string
30 + updateEvery int
31 +
32 + cmd *exec.Cmd
33 + done chan struct{}
34 +
35 + mux sync.Mutex
36 + lastSample string
37 +}
38 +
39 +func (e *intelGpuTopExec) run() error {
40 + refresh := 900
41 + if e.updateEvery > 1 {
42 + refresh = e.updateEvery*1000 - 500 // milliseconds
43 + }
44 +
45 + cmd := exec.Command(e.binPath, "-J", "-s", strconv.Itoa(refresh))
46 +
47 + r, err := cmd.StdoutPipe()
48 + if err != nil {
49 + return err
50 + }
51 +
52 + if err := cmd.Start(); err != nil {
53 + return err
54 + }
55 +
56 + firstSample := make(chan struct{}, 1)
57 + done := make(chan struct{})
58 + e.cmd = cmd
59 + e.done = done
60 +
61 + go func() {
62 + defer close(done)
63 + sc := bufio.NewScanner(r)
64 + var buf bytes.Buffer
65 + var n int
66 +
67 + for sc.Scan() {
68 + if n++; n > 1000 {
69 + break
70 + }
71 +
72 + text := sc.Text()
73 +
74 + if buf.Cap() == 0 && text != "{" || text == "" {
75 + continue
76 + }
77 +
78 + if text == "}," {
79 + text = "}"
80 + }
81 +
82 + buf.WriteString(text + "\n")
83 +
84 + if text[0] == '}' {
85 + e.mux.Lock()
86 + e.lastSample = buf.String()
87 + e.mux.Unlock()
88 +
89 + select {
90 + case firstSample <- struct{}{}:
91 + default:
92 + }
93 +
94 + buf.Reset()
95 + n = 0
96 + }
97 + }
98 + }()
99 +
100 + select {
101 + case <-e.done:
102 + _ = e.stop()
103 + return errors.New("process exited before the first sample was collected")
104 + case <-time.After(time.Second * 3):
105 + _ = e.stop()
106 + return errors.New("timed out waiting for first sample")
107 + case <-firstSample:
108 + return nil
109 + }
110 +}
111 +
112 +func (e *intelGpuTopExec) queryGPUSummaryJson() ([]byte, error) {
113 + select {
114 + case <-e.done:
115 + return nil, errors.New("process has already exited")
116 + default:
117 + }
118 +
119 + e.mux.Lock()
120 + defer e.mux.Unlock()
121 +
122 + return []byte(e.lastSample), nil
123 +}
124 +
125 +func (e *intelGpuTopExec) stop() error {
126 + if e.cmd == nil || e.cmd.Process == nil {
127 + return nil
128 + }
129 +
130 + _ = e.cmd.Process.Kill()
131 + _, _ = e.cmd.Process.Wait()
132 + e.cmd = nil
133 +
134 + select {
135 + case <-e.done:
136 + return nil
137 + case <-time.After(time.Second * 2):
138 + return errors.New("timed out waiting for process to exit")
139 + }
140 +}
src/go/collectors/go.d.plugin/modules/intelgpu/init.go new
+22
@@ -0,0 +1,22 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + "fmt"
7 + "os"
8 + "os/exec"
9 +)
10 +
11 +func (ig *IntelGPU) initIntelGPUTopExec() (intelGpuTop, error) {
12 + binPath := ig.BinaryPath
13 + if _, err := os.Stat(binPath); os.IsNotExist(err) {
14 + path, err := exec.LookPath(ig.binName)
15 + if err != nil {
16 + return nil, fmt.Errorf("error on lookup '%s': %v", ig.binName, err)
17 + }
18 + binPath = path
19 + }
20 +
21 + return newIntelGpuTopExec(binPath, ig.UpdateEvery)
22 +}
src/go/collectors/go.d.plugin/modules/intelgpu/intelgpu.go new
+110
@@ -0,0 +1,110 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + _ "embed"
7 + "errors"
8 +
9 + "github.com/netdata/netdata/go/go.d.plugin/agent/module"
10 +)
11 +
12 +//go:embed "config_schema.json"
13 +var configSchema string
14 +
15 +func init() {
16 + module.Register("intelgpu", module.Creator{
17 + Create: func() module.Module { return New() },
18 + JobConfigSchema: configSchema,
19 + })
20 +}
21 +
22 +func New() *IntelGPU {
23 + return &IntelGPU{
24 + Config: Config{
25 + BinaryPath: "/usr/bin/intel_gpu_top",
26 + },
27 + binName: "intel_gpu_top",
28 + charts: charts.Copy(),
29 + engines: make(map[string]bool),
30 + }
31 +}
32 +
33 +type Config struct {
34 + UpdateEvery int `yaml:"update_every" json:"update_every"`
35 + BinaryPath string `yaml:"binary_path" json:"binary_path"`
36 +}
37 +
38 +type (
39 + IntelGPU struct {
40 + module.Base
41 + Config `yaml:",inline" json:""`
42 +
43 + charts *module.Charts
44 +
45 + exec intelGpuTop
46 + binName string
47 +
48 + engines map[string]bool
49 + }
50 + intelGpuTop interface {
51 + queryGPUSummaryJson() ([]byte, error)
52 + stop() error
53 + }
54 +)
55 +
56 +func (ig *IntelGPU) Configuration() any {
57 + return ig.Config
58 +}
59 +
60 +func (ig *IntelGPU) Init() error {
61 + topExec, err := ig.initIntelGPUTopExec()
62 + if err != nil {
63 + ig.Error(err)
64 + return err
65 + }
66 +
67 + ig.exec = topExec
68 +
69 + return nil
70 +}
71 +
72 +func (ig *IntelGPU) Check() error {
73 + mx, err := ig.collect()
74 + if err != nil {
75 + ig.Error(err)
76 + return err
77 + }
78 +
79 + if len(mx) == 0 {
80 + return errors.New("no metrics collected")
81 + }
82 +
83 + return nil
84 +}
85 +
86 +func (ig *IntelGPU) Charts() *module.Charts {
87 + return ig.charts
88 +}
89 +
90 +func (ig *IntelGPU) Collect() map[string]int64 {
91 + mx, err := ig.collect()
92 + if err != nil {
93 + ig.Error(err)
94 + }
95 +
96 + if len(mx) == 0 {
97 + return nil
98 + }
99 +
100 + return mx
101 +}
102 +
103 +func (ig *IntelGPU) Cleanup() {
104 + if ig.exec != nil {
105 + if err := ig.exec.stop(); err != nil {
106 + ig.Error(err)
107 + }
108 + ig.exec = nil
109 + }
110 +}
src/go/collectors/go.d.plugin/modules/intelgpu/intelgpu_test.go new
+200
@@ -0,0 +1,200 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package intelgpu
4 +
5 +import (
6 + "errors"
7 + "os"
8 + "testing"
9 +
10 + "github.com/stretchr/testify/assert"
11 + "github.com/stretchr/testify/require"
12 +)
13 +
14 +var (
15 + dataConfigJSON, _ = os.ReadFile("testdata/config.json")
16 + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
17 +
18 + dataIntelTopGpuJSON, _ = os.ReadFile("testdata/igt.json")
19 +)
20 +
21 +func Test_testDataIsValid(t *testing.T) {
22 + for name, data := range map[string][]byte{
23 + "dataConfigJSON": dataConfigJSON,
24 + "dataConfigYAML": dataConfigYAML,
25 + "dataIntelTopGpuJSON": dataIntelTopGpuJSON,
26 + } {
27 + require.NotNil(t, data, name)
28 + }
29 +}
30 +
31 +func TestIntelGPU_Init(t *testing.T) {
32 + tests := map[string]struct {
33 + prepare func(igt *IntelGPU)
34 + wantFail bool
35 + }{
36 + "fails if can't find intel_gpu_top": {
37 + wantFail: true,
38 + prepare: func(igt *IntelGPU) {
39 + igt.binName += "!!!"
40 + },
41 + },
42 + }
43 +
44 + for name, test := range tests {
45 + t.Run(name, func(t *testing.T) {
46 + igt := New()
47 +
48 + test.prepare(igt)
49 +
50 + if test.wantFail {
51 + assert.Error(t, igt.Init())
52 + } else {
53 + assert.NoError(t, igt.Init())
54 + }
55 + })
56 + }
57 +}
58 +
59 +func TestIntelGPU_Check(t *testing.T) {
60 + tests := map[string]struct {
61 + prepareMock func() *mockIntelGpuTop
62 + wantFail bool
63 + }{
64 + "success case": {
65 + prepareMock: prepareMockOK,
66 + wantFail: false,
67 + },
68 + "fail on error": {
69 + prepareMock: prepareMockErrOnGPUSummaryJson,
70 + wantFail: true,
71 + },
72 + }
73 +
74 + for name, test := range tests {
75 + t.Run(name, func(t *testing.T) {
76 + igt := New()
77 + mock := test.prepareMock()
78 + igt.exec = mock
79 +
80 + if test.wantFail {
81 + assert.Error(t, igt.Check())
82 + } else {
83 + assert.NoError(t, igt.Check())
84 + }
85 + })
86 + }
87 +}
88 +
89 +func TestIntelGPU_Collect(t *testing.T) {
90 + tests := map[string]struct {
91 + prepareMock func() *mockIntelGpuTop
92 + wantMetrics map[string]int64
93 + }{
94 + "success case": {
95 + prepareMock: prepareMockOK,
96 + wantMetrics: map[string]int64{
97 + "engine_Blitter/0_busy": 0,
98 + "engine_Render/3D/0_busy": 9609,
99 + "engine_Video/0_busy": 7295,
100 + "engine_Video/1_busy": 7740,
101 + "engine_VideoEnhance/0_busy": 0,
102 + "frequency_actual": 125308,
103 + "power_gpu": 323,
104 + "power_package": 1665,
105 + },
106 + },
107 + "fail on error": {
108 + prepareMock: prepareMockErrOnGPUSummaryJson,
109 + wantMetrics: nil,
110 + },
111 + }
112 +
113 + for name, test := range tests {
114 + t.Run(name, func(t *testing.T) {
115 + igt := New()
116 + mock := test.prepareMock()
117 + igt.exec = mock
118 +
119 + mx := igt.Collect()
120 +
121 + assert.Equal(t, test.wantMetrics, mx)
122 + if len(test.wantMetrics) > 0 {
123 + assert.Len(t, *igt.Charts(), len(charts)+len(igt.engines))
124 + }
125 + })
126 + }
127 +}
128 +
129 +func TestIntelGPU_Cleanup(t *testing.T) {
130 + tests := map[string]struct {
131 + prepare func() *IntelGPU
132 + }{
133 + "not initialized exec": {
134 + prepare: func() *IntelGPU {
135 + return New()
136 + },
137 + },
138 + "after check": {
139 + prepare: func() *IntelGPU {
140 + igt := New()
141 + igt.exec = prepareMockOK()
142 + _ = igt.Check()
143 + return igt
144 + },
145 + },
146 + "after collect": {
147 + prepare: func() *IntelGPU {
148 + igt := New()
149 + igt.exec = prepareMockOK()
150 + _ = igt.Collect()
151 + return igt
152 + },
153 + },
154 + }
155 +
156 + for name, test := range tests {
157 + t.Run(name, func(t *testing.T) {
158 + igt := test.prepare()
159 +
160 + mock, ok := igt.exec.(*mockIntelGpuTop)
161 +
162 + assert.NotPanics(t, igt.Cleanup)
163 +
164 + if ok {
165 + assert.True(t, mock.stopCalled)
166 + }
167 + })
168 + }
169 +}
170 +
171 +func prepareMockOK() *mockIntelGpuTop {
172 + return &mockIntelGpuTop{
173 + gpuSummaryJson: dataIntelTopGpuJSON,
174 + }
175 +}
176 +
177 +func prepareMockErrOnGPUSummaryJson() *mockIntelGpuTop {
178 + return &mockIntelGpuTop{
179 + errOnQueryGPUSummaryJson: true,
180 + }
181 +}
182 +
183 +type mockIntelGpuTop struct {
184 + errOnQueryGPUSummaryJson bool
185 + gpuSummaryJson []byte
186 +
187 + stopCalled bool
188 +}
189 +
190 +func (m *mockIntelGpuTop) queryGPUSummaryJson() ([]byte, error) {
191 + if m.errOnQueryGPUSummaryJson {
192 + return nil, errors.New("error on mock.queryGPUSummaryJson()")
193 + }
194 + return m.gpuSummaryJson, nil
195 +}
196 +
197 +func (m *mockIntelGpuTop) stop() error {
198 + m.stopCalled = true
199 + return nil
200 +}
src/go/collectors/go.d.plugin/modules/intelgpu/metadata.yaml new
+115
@@ -0,0 +1,115 @@
1 +plugin_name: go.d.plugin
2 +modules:
3 + - meta:
4 + id: collector-go.d.plugin-intelgpu
5 + plugin_name: go.d.plugin
6 + module_name: intelgpu
7 + monitored_instance:
8 + name: Intel GPU
9 + link: https://www.intel.com/
10 + icon_filename: intel.svg
11 + categories:
12 + - data-collection.hardware-devices-and-sensors
13 + keywords:
14 + - intel
15 + - gpu
16 + - hardware
17 + related_resources:
18 + integrations:
19 + list: []
20 + info_provided_to_referring_integrations:
21 + description: ""
22 + most_popular: false
23 + overview:
24 + data_collection:
25 + metrics_description: |
26 + This collector monitors Intel integrated GPUs performance metrics using
27 + the [intel_gpu_top](https://manpages.debian.org/testing/intel-gpu-tools/intel_gpu_top.1.en.html) CLI tool.
28 + method_description: ""
29 + supported_platforms:
30 + include: []
31 + exclude: []
32 + multi_instance: true
33 + additional_permissions:
34 + description: ""
35 + default_behavior:
36 + auto_detection:
37 + description: ""
38 + limits:
39 + description: ""
40 + performance_impact:
41 + description: ""
42 + setup:
43 + prerequisites:
44 + list: []
45 + configuration:
46 + file:
47 + name: go.d/intelgpu.conf
48 + options:
49 + description: |
50 + The following options can be defined globally: update_every.
51 + folding:
52 + title: Config options
53 + enabled: true
54 + list:
55 + - name: update_every
56 + description: Data collection frequency.
57 + default_value: 1
58 + required: false
59 + - name: binary_path
60 + description: Path to the intel_gpu_top binary. If an absolute path is provided, the collector will use it directly; otherwise, it will search for the binary in directories specified in the PATH environment variable.
61 + default_value: /usr/bin/intel_gpu_top
62 + required: false
63 + examples:
64 + folding:
65 + title: Config
66 + enabled: true
67 + list:
68 + - name: Custom binary path
69 + description: The executable is not in the directories specified in the PATH environment variable.
70 + config: |
71 + jobs:
72 + - name: nvidia_smi
73 + binary_path: /usr/local/sbin/intel_gpu_top
74 + troubleshooting:
75 + problems:
76 + list: []
77 + alerts: []
78 + metrics:
79 + folding:
80 + title: Metrics
81 + enabled: false
82 + description: ""
83 + availability: []
84 + scopes:
85 + - name: global
86 + description: These metrics refer to the Intel GPU.
87 + labels: []
88 + metrics:
89 + - name: intelgpu.frequency
90 + description: Intel GPU frequency
91 + unit: MHz
92 + chart_type: line
93 + dimensions:
94 + - name: frequency
95 + - name: intelgpu.power
96 + description: Intel GPU power
97 + unit: Watts
98 + chart_type: line
99 + dimensions:
100 + - name: gpu
101 + - name: package
102 + - name: engine
103 + description: These metrics refer to the GPU hardware engine.
104 + labels:
105 + - name: engine
106 + description: Engine name (Render/3D, Blitter, VideoEnhance, Video, Compute).
107 + - name: engine_instance
108 + description: Engine instance (e.g. Render/3D/0, Video/0, Video/1).
109 + metrics:
110 + - name: intelgpu.engine_busy_perc
111 + description: Intel GPU engine busy time percentage
112 + unit: percentage
113 + chart_type: line
114 + dimensions:
115 + - name: busy
src/go/collectors/go.d.plugin/modules/intelgpu/testdata/config.json new
+4
@@ -0,0 +1,4 @@
1 +{
2 + "update_every": 123,
3 + "binary_path": "ok"
4 +}
src/go/collectors/go.d.plugin/modules/intelgpu/testdata/config.yaml new
+2
@@ -0,0 +1,2 @@
1 +update_every: 123
2 +binary_path: "ok"
src/go/collectors/go.d.plugin/modules/intelgpu/testdata/igt.json new
+80
@@ -0,0 +1,80 @@
1 +{
2 + "period": {
3 + "duration": 1055.794145,
4 + "unit": "ms"
5 + },
6 + "frequency": {
7 + "requested": 1449.146131,
8 + "actual": 1253.085184,
9 + "unit": "MHz"
10 + },
11 + "interrupts": {
12 + "count": 1757.918443,
13 + "unit": "irq/s"
14 + },
15 + "rc6": {
16 + "value": 0.000000,
17 + "unit": "%"
18 + },
19 + "power": {
20 + "GPU": 3.233528,
21 + "Package": 16.658620,
22 + "unit": "W"
23 + },
24 + "engines": {
25 + "Render/3D/0": {
26 + "busy": 96.092944,
27 + "sema": 0.000000,
28 + "wait": 0.000000,
29 + "unit": "%"
30 + },
31 + "Blitter/0": {
32 + "busy": 0.000000,
33 + "sema": 0.000000,
34 + "wait": 0.000000,
35 + "unit": "%"
36 + },
37 + "Video/0": {
38 + "busy": 72.950675,
39 + "sema": 0.000000,
40 + "wait": 0.000000,
41 + "unit": "%"
42 + },
43 + "Video/1": {
44 + "busy": 77.402254,
45 + "sema": 0.000000,
46 + "wait": 0.000000,
47 + "unit": "%"
48 + },
49 + "VideoEnhance/0": {
50 + "busy": 0.000000,
51 + "sema": 0.000000,
52 + "wait": 0.000000,
53 + "unit": "%"
54 + }
55 + },
56 + "clients": {
57 + "4292239459": {
58 + "name": "ffmpeg",
59 + "pid": "2727837",
60 + "engine-classes": {
61 + "Render/3D": {
62 + "busy": "101.396726",
63 + "unit": "%"
64 + },
65 + "Blitter": {
66 + "busy": "0.000000",
67 + "unit": "%"
68 + },
69 + "Video": {
70 + "busy": "159.292435",
71 + "unit": "%"
72 + },
73 + "VideoEnhance": {
74 + "busy": "0.000000",
75 + "unit": "%"
76 + }
77 + }
78 + }
79 + }
80 +}