From f5afcc169c43bfd8ec1c3a901c79318958278b41 Mon Sep 17 00:00:00 2001 From: Sven Rebhan <36194019+srebhan@users.noreply.github.com> Date: Fri, 28 Jul 2023 21:38:35 +0200 Subject: [PATCH] feat(inputs.nvidia_smi): Support newer data schema versions (#13678) --- plugins/inputs/nvidia_smi/common/setters.go | 45 + plugins/inputs/nvidia_smi/nvidia_smi.go | 299 ++----- plugins/inputs/nvidia_smi/nvidia_smi_test.go | 51 +- .../inputs/nvidia_smi/schema_v11/parser.go | 66 ++ plugins/inputs/nvidia_smi/schema_v11/types.go | 107 +++ .../inputs/nvidia_smi/schema_v12/parser.go | 75 ++ plugins/inputs/nvidia_smi/schema_v12/types.go | 255 ++++++ .../nvidia_smi/testdata/rtx-3080-v12.xml | 786 ++++++++++++++++++ 8 files changed, 1442 insertions(+), 242 deletions(-) create mode 100644 plugins/inputs/nvidia_smi/common/setters.go create mode 100644 plugins/inputs/nvidia_smi/schema_v11/parser.go create mode 100644 plugins/inputs/nvidia_smi/schema_v11/types.go create mode 100644 plugins/inputs/nvidia_smi/schema_v12/parser.go create mode 100644 plugins/inputs/nvidia_smi/schema_v12/types.go create mode 100644 plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml diff --git a/plugins/inputs/nvidia_smi/common/setters.go b/plugins/inputs/nvidia_smi/common/setters.go new file mode 100644 index 000000000..4c5e07725 --- /dev/null +++ b/plugins/inputs/nvidia_smi/common/setters.go @@ -0,0 +1,45 @@ +package common + +import ( + "strconv" + "strings" +) + +func SetTagIfUsed(m map[string]string, k, v string) { + if v != "" { + m[k] = v + } +} + +func SetIfUsed(t string, m map[string]interface{}, k, v string) { + vals := strings.Fields(v) + if len(vals) < 1 { + return + } + + val := vals[0] + if k == "pcie_link_width_current" { + val = strings.TrimSuffix(vals[0], "x") + } + + switch t { + case "float": + if val != "" { + f, err := strconv.ParseFloat(val, 64) + if err == nil { + m[k] = f + } + } + case "int": + if val != "" && val != "N/A" { + i, err := strconv.Atoi(val) + if err == nil { + m[k] = i + } + } + case "str": + if val != "" && val != "N/A" { + m[k] = val + } + } +} diff --git a/plugins/inputs/nvidia_smi/nvidia_smi.go b/plugins/inputs/nvidia_smi/nvidia_smi.go index 037be8828..45e8a2c2c 100644 --- a/plugins/inputs/nvidia_smi/nvidia_smi.go +++ b/plugins/inputs/nvidia_smi/nvidia_smi.go @@ -2,30 +2,36 @@ package nvidia_smi import ( + "bytes" _ "embed" "encoding/xml" + "errors" "fmt" + "io" "os" "os/exec" - "strconv" "strings" + "sync" "time" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/schema_v11" + "github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/schema_v12" ) //go:embed sample.conf var sampleConfig string -const measurement = "nvidia_smi" - // NvidiaSMI holds the methods for this plugin type NvidiaSMI struct { - BinPath string - Timeout config.Duration + BinPath string `toml:"bin_path"` + Timeout config.Duration `toml:"timeout"` + Log telegraf.Logger `toml:"-"` + + once sync.Once } func (*NvidiaSMI) SampleConfig() string { @@ -47,17 +53,61 @@ func (smi *NvidiaSMI) Init() error { // Gather implements the telegraf interface func (smi *NvidiaSMI) Gather(acc telegraf.Accumulator) error { - data, err := smi.pollSMI() + // Construct and execute metrics query + data, err := internal.CombinedOutputTimeout(exec.Command(smi.BinPath, "-q", "-x"), time.Duration(smi.Timeout)) if err != nil { - return err + return fmt.Errorf("calling %q failed: %w", smi.BinPath, err) } - err = gatherNvidiaSMI(data, acc) - if err != nil { - return err + // Parse the output + return smi.parse(acc, data) +} + +func (smi *NvidiaSMI) parse(acc telegraf.Accumulator, data []byte) error { + schema := "v11" + + buf := bytes.NewBuffer(data) + decoder := xml.NewDecoder(buf) + for { + token, err := decoder.Token() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return fmt.Errorf("reading token failed: %w", err) + } + d, ok := token.(xml.Directive) + if !ok { + continue + } + directive := string(d) + if !strings.HasPrefix(directive, "DOCTYPE") { + continue + } + parts := strings.Split(directive, " ") + s := strings.Trim(parts[len(parts)-1], "\" ") + if strings.HasPrefix(s, "nvsmi_device_") && strings.HasSuffix(s, ".dtd") { + schema = strings.TrimSuffix(strings.TrimPrefix(s, "nvsmi_device_"), ".dtd") + } else { + smi.Log.Debugf("Cannot find schema version in %q", directive) + } + break + } + smi.Log.Debugf("Using schema version in %s", schema) + + switch schema { + case "v10", "v11": + return schema_v11.Parse(acc, data) + case "v12": + return schema_v12.Parse(acc, data) } - return nil + smi.once.Do(func() { + smi.Log.Warnf(`Unknown schema version %q, using latest know schema for parsing. + Please report this as an issue to https://github.com/influxdata/telegraf together + with a sample output of 'nvidia_smi -q -x'!`, schema) + }) + return schema_v12.Parse(acc, data) } func init() { @@ -68,230 +118,3 @@ func init() { } }) } - -func (smi *NvidiaSMI) pollSMI() ([]byte, error) { - // Construct and execute metrics query - ret, err := internal.CombinedOutputTimeout(exec.Command(smi.BinPath, "-q", "-x"), time.Duration(smi.Timeout)) - if err != nil { - return nil, err - } - return ret, nil -} - -func gatherNvidiaSMI(ret []byte, acc telegraf.Accumulator) error { - smi := &SMI{} - err := xml.Unmarshal(ret, smi) - if err != nil { - return err - } - - metrics := smi.genTagsFields() - - for _, metric := range metrics { - acc.AddFields(measurement, metric.fields, metric.tags) - } - - return nil -} - -type metric struct { - tags map[string]string - fields map[string]interface{} -} - -func (s *SMI) genTagsFields() []metric { - metrics := []metric{} - for i, gpu := range s.GPU { - tags := map[string]string{ - "index": strconv.Itoa(i), - } - fields := map[string]interface{}{} - - setTagIfUsed(tags, "pstate", gpu.PState) - setTagIfUsed(tags, "name", gpu.ProdName) - setTagIfUsed(tags, "uuid", gpu.UUID) - setTagIfUsed(tags, "compute_mode", gpu.ComputeMode) - - setIfUsed("str", fields, "driver_version", s.DriverVersion) - setIfUsed("str", fields, "cuda_version", s.CUDAVersion) - setIfUsed("int", fields, "fan_speed", gpu.FanSpeed) - setIfUsed("int", fields, "memory_total", gpu.Memory.Total) - setIfUsed("int", fields, "memory_used", gpu.Memory.Used) - setIfUsed("int", fields, "memory_free", gpu.Memory.Free) - setIfUsed("int", fields, "memory_reserved", gpu.Memory.Reserved) - setIfUsed("int", fields, "retired_pages_multiple_single_bit", gpu.RetiredPages.MultipleSingleBit.Count) - setIfUsed("int", fields, "retired_pages_double_bit", gpu.RetiredPages.DoubleBit.Count) - setIfUsed("str", fields, "retired_pages_blacklist", gpu.RetiredPages.PendingBlacklist) - setIfUsed("str", fields, "retired_pages_pending", gpu.RetiredPages.PendingRetirement) - setIfUsed("int", fields, "remapped_rows_correctable", gpu.RemappedRows.Correctable) - setIfUsed("int", fields, "remapped_rows_uncorrectable", gpu.RemappedRows.Uncorrectable) - setIfUsed("str", fields, "remapped_rows_pending", gpu.RemappedRows.Pending) - setIfUsed("str", fields, "remapped_rows_failure", gpu.RemappedRows.Failure) - setIfUsed("int", fields, "temperature_gpu", gpu.Temp.GPUTemp) - setIfUsed("int", fields, "utilization_gpu", gpu.Utilization.GPU) - setIfUsed("int", fields, "utilization_memory", gpu.Utilization.Memory) - setIfUsed("int", fields, "utilization_encoder", gpu.Utilization.Encoder) - setIfUsed("int", fields, "utilization_decoder", gpu.Utilization.Decoder) - setIfUsed("int", fields, "pcie_link_gen_current", gpu.PCI.LinkInfo.PCIEGen.CurrentLinkGen) - setIfUsed("int", fields, "pcie_link_width_current", gpu.PCI.LinkInfo.LinkWidth.CurrentLinkWidth) - setIfUsed("int", fields, "encoder_stats_session_count", gpu.Encoder.SessionCount) - setIfUsed("int", fields, "encoder_stats_average_fps", gpu.Encoder.AverageFPS) - setIfUsed("int", fields, "encoder_stats_average_latency", gpu.Encoder.AverageLatency) - setIfUsed("int", fields, "fbc_stats_session_count", gpu.FBC.SessionCount) - setIfUsed("int", fields, "fbc_stats_average_fps", gpu.FBC.AverageFPS) - setIfUsed("int", fields, "fbc_stats_average_latency", gpu.FBC.AverageLatency) - setIfUsed("int", fields, "clocks_current_graphics", gpu.Clocks.Graphics) - setIfUsed("int", fields, "clocks_current_sm", gpu.Clocks.SM) - setIfUsed("int", fields, "clocks_current_memory", gpu.Clocks.Memory) - setIfUsed("int", fields, "clocks_current_video", gpu.Clocks.Video) - - setIfUsed("float", fields, "power_draw", gpu.Power.PowerDraw) - metrics = append(metrics, metric{tags, fields}) - } - return metrics -} - -func setTagIfUsed(m map[string]string, k, v string) { - if v != "" { - m[k] = v - } -} - -func setIfUsed(t string, m map[string]interface{}, k, v string) { - vals := strings.Fields(v) - if len(vals) < 1 { - return - } - - val := vals[0] - if k == "pcie_link_width_current" { - val = strings.TrimSuffix(vals[0], "x") - } - - switch t { - case "float": - if val != "" { - f, err := strconv.ParseFloat(val, 64) - if err == nil { - m[k] = f - } - } - case "int": - if val != "" && val != "N/A" { - i, err := strconv.Atoi(val) - if err == nil { - m[k] = i - } - } - case "str": - if val != "" && val != "N/A" { - m[k] = val - } - } -} - -// SMI defines the structure for the output of _nvidia-smi -q -x_. -type SMI struct { - GPU GPU `xml:"gpu"` - DriverVersion string `xml:"driver_version"` - CUDAVersion string `xml:"cuda_version"` -} - -// GPU defines the structure of the GPU portion of the smi output. -type GPU []struct { - FanSpeed string `xml:"fan_speed"` // int - Memory MemoryStats `xml:"fb_memory_usage"` - RetiredPages MemoryRetiredPages `xml:"retired_pages"` - RemappedRows MemoryRemappedRows `xml:"remapped_rows"` - PState string `xml:"performance_state"` - Temp TempStats `xml:"temperature"` - ProdName string `xml:"product_name"` - UUID string `xml:"uuid"` - ComputeMode string `xml:"compute_mode"` - Utilization UtilizationStats `xml:"utilization"` - Power PowerReadings `xml:"power_readings"` - PCI PCI `xml:"pci"` - Encoder EncoderStats `xml:"encoder_stats"` - FBC FBCStats `xml:"fbc_stats"` - Clocks ClockStats `xml:"clocks"` -} - -// MemoryStats defines the structure of the memory portions in the smi output. -type MemoryStats struct { - Total string `xml:"total"` // int - Used string `xml:"used"` // int - Free string `xml:"free"` // int - Reserved string `xml:"reserved"` // int -} - -// MemoryRetiredPages defines the structure of the retired pages portions in the smi output. -type MemoryRetiredPages struct { - MultipleSingleBit struct { - Count string `xml:"retired_count"` // int - } `xml:"multiple_single_bit_retirement"` - DoubleBit struct { - Count string `xml:"retired_count"` // int - } `xml:"double_bit_retirement"` - PendingBlacklist string `xml:"pending_blacklist"` // Yes/No - PendingRetirement string `xml:"pending_retirement"` // Yes/No -} - -// MemoryRemappedRows defines the structure of the remapped rows portions in the smi output. -type MemoryRemappedRows struct { - Correctable string `xml:"remapped_row_corr"` // int - Uncorrectable string `xml:"remapped_row_unc"` // int - Pending string `xml:"remapped_row_pending"` // Yes/No - Failure string `xml:"remapped_row_failure"` // Yes/No -} - -// TempStats defines the structure of the temperature portion of the smi output. -type TempStats struct { - GPUTemp string `xml:"gpu_temp"` // int -} - -// UtilizationStats defines the structure of the utilization portion of the smi output. -type UtilizationStats struct { - GPU string `xml:"gpu_util"` // int - Memory string `xml:"memory_util"` // int - Encoder string `xml:"encoder_util"` // int - Decoder string `xml:"decoder_util"` // int -} - -// PowerReadings defines the structure of the power_readings portion of the smi output. -type PowerReadings struct { - PowerDraw string `xml:"power_draw"` // float -} - -// PCI defines the structure of the pci portion of the smi output. -type PCI struct { - LinkInfo struct { - PCIEGen struct { - CurrentLinkGen string `xml:"current_link_gen"` // int - } `xml:"pcie_gen"` - LinkWidth struct { - CurrentLinkWidth string `xml:"current_link_width"` // int - } `xml:"link_widths"` - } `xml:"pci_gpu_link_info"` -} - -// EncoderStats defines the structure of the encoder_stats portion of the smi output. -type EncoderStats struct { - SessionCount string `xml:"session_count"` // int - AverageFPS string `xml:"average_fps"` // int - AverageLatency string `xml:"average_latency"` // int -} - -// FBCStats defines the structure of the fbc_stats portion of the smi output. -type FBCStats struct { - SessionCount string `xml:"session_count"` // int - AverageFPS string `xml:"average_fps"` // int - AverageLatency string `xml:"average_latency"` // int -} - -// ClockStats defines the structure of the clocks portion of the smi output. -type ClockStats struct { - Graphics string `xml:"graphics_clock"` // int - SM string `xml:"sm_clock"` // int - Memory string `xml:"mem_clock"` // int - Video string `xml:"video_clock"` // int -} diff --git a/plugins/inputs/nvidia_smi/nvidia_smi_test.go b/plugins/inputs/nvidia_smi/nvidia_smi_test.go index 5220aa269..b954560ce 100644 --- a/plugins/inputs/nvidia_smi/nvidia_smi_test.go +++ b/plugins/inputs/nvidia_smi/nvidia_smi_test.go @@ -227,17 +227,60 @@ func TestGatherValidXML(t *testing.T) { time.Unix(0, 0)), }, }, + { + name: "RTC 3080 schema v12", + filename: "rtx-3080-v12.xml", + expected: []telegraf.Metric{ + testutil.MustMetric( + "nvidia_smi", + map[string]string{ + "compute_mode": "Default", + "index": "0", + "name": "NVIDIA GeForce RTX 3080", + "arch": "Ampere", + "pstate": "P8", + "uuid": "GPU-19d6d965-2acc-f646-00f8-4c76979aabb4", + }, + map[string]interface{}{ + "clocks_current_graphics": 210, + "clocks_current_memory": 405, + "clocks_current_sm": 210, + "clocks_current_video": 555, + "cuda_version": "12.2", + "driver_version": "536.40", + "encoder_stats_average_fps": 0, + "encoder_stats_average_latency": 0, + "encoder_stats_session_count": 0, + "fbc_stats_average_fps": 0, + "fbc_stats_average_latency": 0, + "fbc_stats_session_count": 0, + "fan_speed": 0, + "power_draw": 22.78, + "memory_free": 8938, + "memory_total": 10240, + "memory_used": 1128, + "memory_reserved": 173, + "pcie_link_gen_current": 4, + "pcie_link_width_current": 16, + "temperature_gpu": 31, + "utilization_gpu": 0, + "utilization_memory": 37, + "utilization_encoder": 0, + "utilization_decoder": 0, + }, + time.Unix(1689872450, 0)), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var acc testutil.Accumulator - octets, err := os.ReadFile(filepath.Join("testdata", tt.filename)) require.NoError(t, err) - err = gatherNvidiaSMI(octets, &acc) - require.NoError(t, err) + plugin := &NvidiaSMI{Log: &testutil.Logger{}} + var acc testutil.Accumulator + require.NoError(t, plugin.parse(&acc, octets)) testutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime()) }) } diff --git a/plugins/inputs/nvidia_smi/schema_v11/parser.go b/plugins/inputs/nvidia_smi/schema_v11/parser.go new file mode 100644 index 000000000..1e16bd660 --- /dev/null +++ b/plugins/inputs/nvidia_smi/schema_v11/parser.go @@ -0,0 +1,66 @@ +package schema_v11 + +import ( + "encoding/xml" + "strconv" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/common" +) + +func Parse(acc telegraf.Accumulator, buf []byte) error { + var s smi + if err := xml.Unmarshal(buf, &s); err != nil { + return err + } + + for i, gpu := range s.GPU { + tags := map[string]string{ + "index": strconv.Itoa(i), + } + fields := map[string]interface{}{} + + common.SetTagIfUsed(tags, "pstate", gpu.PState) + common.SetTagIfUsed(tags, "name", gpu.ProdName) + common.SetTagIfUsed(tags, "uuid", gpu.UUID) + common.SetTagIfUsed(tags, "compute_mode", gpu.ComputeMode) + + common.SetIfUsed("str", fields, "driver_version", s.DriverVersion) + common.SetIfUsed("str", fields, "cuda_version", s.CUDAVersion) + common.SetIfUsed("int", fields, "fan_speed", gpu.FanSpeed) + common.SetIfUsed("int", fields, "memory_total", gpu.Memory.Total) + common.SetIfUsed("int", fields, "memory_used", gpu.Memory.Used) + common.SetIfUsed("int", fields, "memory_free", gpu.Memory.Free) + common.SetIfUsed("int", fields, "memory_reserved", gpu.Memory.Reserved) + common.SetIfUsed("int", fields, "retired_pages_multiple_single_bit", gpu.RetiredPages.MultipleSingleBit.Count) + common.SetIfUsed("int", fields, "retired_pages_double_bit", gpu.RetiredPages.DoubleBit.Count) + common.SetIfUsed("str", fields, "retired_pages_blacklist", gpu.RetiredPages.PendingBlacklist) + common.SetIfUsed("str", fields, "retired_pages_pending", gpu.RetiredPages.PendingRetirement) + common.SetIfUsed("int", fields, "remapped_rows_correctable", gpu.RemappedRows.Correctable) + common.SetIfUsed("int", fields, "remapped_rows_uncorrectable", gpu.RemappedRows.Uncorrectable) + common.SetIfUsed("str", fields, "remapped_rows_pending", gpu.RemappedRows.Pending) + common.SetIfUsed("str", fields, "remapped_rows_failure", gpu.RemappedRows.Failure) + common.SetIfUsed("int", fields, "temperature_gpu", gpu.Temp.GPUTemp) + common.SetIfUsed("int", fields, "utilization_gpu", gpu.Utilization.GPU) + common.SetIfUsed("int", fields, "utilization_memory", gpu.Utilization.Memory) + common.SetIfUsed("int", fields, "utilization_encoder", gpu.Utilization.Encoder) + common.SetIfUsed("int", fields, "utilization_decoder", gpu.Utilization.Decoder) + common.SetIfUsed("int", fields, "pcie_link_gen_current", gpu.PCI.LinkInfo.PCIEGen.CurrentLinkGen) + common.SetIfUsed("int", fields, "pcie_link_width_current", gpu.PCI.LinkInfo.LinkWidth.CurrentLinkWidth) + common.SetIfUsed("int", fields, "encoder_stats_session_count", gpu.Encoder.SessionCount) + common.SetIfUsed("int", fields, "encoder_stats_average_fps", gpu.Encoder.AverageFPS) + common.SetIfUsed("int", fields, "encoder_stats_average_latency", gpu.Encoder.AverageLatency) + common.SetIfUsed("int", fields, "fbc_stats_session_count", gpu.FBC.SessionCount) + common.SetIfUsed("int", fields, "fbc_stats_average_fps", gpu.FBC.AverageFPS) + common.SetIfUsed("int", fields, "fbc_stats_average_latency", gpu.FBC.AverageLatency) + common.SetIfUsed("int", fields, "clocks_current_graphics", gpu.Clocks.Graphics) + common.SetIfUsed("int", fields, "clocks_current_sm", gpu.Clocks.SM) + common.SetIfUsed("int", fields, "clocks_current_memory", gpu.Clocks.Memory) + common.SetIfUsed("int", fields, "clocks_current_video", gpu.Clocks.Video) + + common.SetIfUsed("float", fields, "power_draw", gpu.Power.PowerDraw) + acc.AddFields("nvidia_smi", fields, tags) + } + + return nil +} diff --git a/plugins/inputs/nvidia_smi/schema_v11/types.go b/plugins/inputs/nvidia_smi/schema_v11/types.go new file mode 100644 index 000000000..9e022c13f --- /dev/null +++ b/plugins/inputs/nvidia_smi/schema_v11/types.go @@ -0,0 +1,107 @@ +package schema_v11 + +// SMI defines the structure for the output of _nvidia-smi -q -x_. +type smi struct { + GPU []GPU `xml:"gpu"` + DriverVersion string `xml:"driver_version"` + CUDAVersion string `xml:"cuda_version"` +} + +// GPU defines the structure of the GPU portion of the smi output. +type GPU struct { + FanSpeed string `xml:"fan_speed"` // int + Memory MemoryStats `xml:"fb_memory_usage"` + RetiredPages MemoryRetiredPages `xml:"retired_pages"` + RemappedRows MemoryRemappedRows `xml:"remapped_rows"` + PState string `xml:"performance_state"` + Temp TempStats `xml:"temperature"` + ProdName string `xml:"product_name"` + UUID string `xml:"uuid"` + ComputeMode string `xml:"compute_mode"` + Utilization UtilizationStats `xml:"utilization"` + Power PowerReadings `xml:"power_readings"` + PCI PCI `xml:"pci"` + Encoder EncoderStats `xml:"encoder_stats"` + FBC FBCStats `xml:"fbc_stats"` + Clocks ClockStats `xml:"clocks"` +} + +// MemoryStats defines the structure of the memory portions in the smi output. +type MemoryStats struct { + Total string `xml:"total"` // int + Used string `xml:"used"` // int + Free string `xml:"free"` // int + Reserved string `xml:"reserved"` // int +} + +// MemoryRetiredPages defines the structure of the retired pages portions in the smi output. +type MemoryRetiredPages struct { + MultipleSingleBit struct { + Count string `xml:"retired_count"` // int + } `xml:"multiple_single_bit_retirement"` + DoubleBit struct { + Count string `xml:"retired_count"` // int + } `xml:"double_bit_retirement"` + PendingBlacklist string `xml:"pending_blacklist"` // Yes/No + PendingRetirement string `xml:"pending_retirement"` // Yes/No +} + +// MemoryRemappedRows defines the structure of the remapped rows portions in the smi output. +type MemoryRemappedRows struct { + Correctable string `xml:"remapped_row_corr"` // int + Uncorrectable string `xml:"remapped_row_unc"` // int + Pending string `xml:"remapped_row_pending"` // Yes/No + Failure string `xml:"remapped_row_failure"` // Yes/No +} + +// TempStats defines the structure of the temperature portion of the smi output. +type TempStats struct { + GPUTemp string `xml:"gpu_temp"` // int +} + +// UtilizationStats defines the structure of the utilization portion of the smi output. +type UtilizationStats struct { + GPU string `xml:"gpu_util"` // int + Memory string `xml:"memory_util"` // int + Encoder string `xml:"encoder_util"` // int + Decoder string `xml:"decoder_util"` // int +} + +// PowerReadings defines the structure of the power_readings portion of the smi output. +type PowerReadings struct { + PowerDraw string `xml:"power_draw"` // float +} + +// PCI defines the structure of the pci portion of the smi output. +type PCI struct { + LinkInfo struct { + PCIEGen struct { + CurrentLinkGen string `xml:"current_link_gen"` // int + } `xml:"pcie_gen"` + LinkWidth struct { + CurrentLinkWidth string `xml:"current_link_width"` // int + } `xml:"link_widths"` + } `xml:"pci_gpu_link_info"` +} + +// EncoderStats defines the structure of the encoder_stats portion of the smi output. +type EncoderStats struct { + SessionCount string `xml:"session_count"` // int + AverageFPS string `xml:"average_fps"` // int + AverageLatency string `xml:"average_latency"` // int +} + +// FBCStats defines the structure of the fbc_stats portion of the smi output. +type FBCStats struct { + SessionCount string `xml:"session_count"` // int + AverageFPS string `xml:"average_fps"` // int + AverageLatency string `xml:"average_latency"` // int +} + +// ClockStats defines the structure of the clocks portion of the smi output. +type ClockStats struct { + Graphics string `xml:"graphics_clock"` // int + SM string `xml:"sm_clock"` // int + Memory string `xml:"mem_clock"` // int + Video string `xml:"video_clock"` // int +} diff --git a/plugins/inputs/nvidia_smi/schema_v12/parser.go b/plugins/inputs/nvidia_smi/schema_v12/parser.go new file mode 100644 index 000000000..ce351991e --- /dev/null +++ b/plugins/inputs/nvidia_smi/schema_v12/parser.go @@ -0,0 +1,75 @@ +package schema_v12 + +import ( + "encoding/xml" + "strconv" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/common" +) + +func Parse(acc telegraf.Accumulator, buf []byte) error { + var s smi + if err := xml.Unmarshal(buf, &s); err != nil { + return err + } + + timestamp := time.Now() + if s.Timestamp != "" { + if t, err := time.ParseInLocation(time.ANSIC, s.Timestamp, time.Local); err == nil { + timestamp = t + } + } + + for i, gpu := range s.Gpu { + tags := map[string]string{ + "index": strconv.Itoa(i), + } + fields := map[string]interface{}{} + + common.SetTagIfUsed(tags, "pstate", gpu.PerformanceState) + common.SetTagIfUsed(tags, "name", gpu.ProductName) + common.SetTagIfUsed(tags, "arch", gpu.ProductArchitecture) + common.SetTagIfUsed(tags, "uuid", gpu.UUID) + common.SetTagIfUsed(tags, "compute_mode", gpu.ComputeMode) + + common.SetIfUsed("str", fields, "driver_version", s.DriverVersion) + common.SetIfUsed("str", fields, "cuda_version", s.CudaVersion) + common.SetIfUsed("int", fields, "fan_speed", gpu.FanSpeed) + common.SetIfUsed("int", fields, "memory_total", gpu.FbMemoryUsage.Total) + common.SetIfUsed("int", fields, "memory_used", gpu.FbMemoryUsage.Used) + common.SetIfUsed("int", fields, "memory_free", gpu.FbMemoryUsage.Free) + common.SetIfUsed("int", fields, "memory_reserved", gpu.FbMemoryUsage.Reserved) + common.SetIfUsed("int", fields, "retired_pages_multiple_single_bit", gpu.RetiredPages.MultipleSingleBitRetirement.RetiredCount) + common.SetIfUsed("int", fields, "retired_pages_double_bit", gpu.RetiredPages.DoubleBitRetirement.RetiredCount) + common.SetIfUsed("str", fields, "retired_pages_blacklist", gpu.RetiredPages.PendingBlacklist) + common.SetIfUsed("str", fields, "retired_pages_pending", gpu.RetiredPages.PendingRetirement) + common.SetIfUsed("int", fields, "remapped_rows_correctable", gpu.RemappedRows.Correctable) + common.SetIfUsed("int", fields, "remapped_rows_uncorrectable", gpu.RemappedRows.Uncorrectable) + common.SetIfUsed("str", fields, "remapped_rows_pending", gpu.RemappedRows.Pending) + common.SetIfUsed("str", fields, "remapped_rows_failure", gpu.RemappedRows.Failure) + common.SetIfUsed("int", fields, "temperature_gpu", gpu.Temperature.GpuTemp) + common.SetIfUsed("int", fields, "utilization_gpu", gpu.Utilization.GpuUtil) + common.SetIfUsed("int", fields, "utilization_memory", gpu.Utilization.MemoryUtil) + common.SetIfUsed("int", fields, "utilization_encoder", gpu.Utilization.EncoderUtil) + common.SetIfUsed("int", fields, "utilization_decoder", gpu.Utilization.DecoderUtil) + common.SetIfUsed("int", fields, "pcie_link_gen_current", gpu.Pci.PciGpuLinkInfo.PcieGen.CurrentLinkGen) + common.SetIfUsed("int", fields, "pcie_link_width_current", gpu.Pci.PciGpuLinkInfo.LinkWidths.CurrentLinkWidth) + common.SetIfUsed("int", fields, "encoder_stats_session_count", gpu.EncoderStats.SessionCount) + common.SetIfUsed("int", fields, "encoder_stats_average_fps", gpu.EncoderStats.AverageFps) + common.SetIfUsed("int", fields, "encoder_stats_average_latency", gpu.EncoderStats.AverageLatency) + common.SetIfUsed("int", fields, "fbc_stats_session_count", gpu.FbcStats.SessionCount) + common.SetIfUsed("int", fields, "fbc_stats_average_fps", gpu.FbcStats.AverageFps) + common.SetIfUsed("int", fields, "fbc_stats_average_latency", gpu.FbcStats.AverageLatency) + common.SetIfUsed("int", fields, "clocks_current_graphics", gpu.Clocks.GraphicsClock) + common.SetIfUsed("int", fields, "clocks_current_sm", gpu.Clocks.SmClock) + common.SetIfUsed("int", fields, "clocks_current_memory", gpu.Clocks.MemClock) + common.SetIfUsed("int", fields, "clocks_current_video", gpu.Clocks.VideoClock) + common.SetIfUsed("float", fields, "power_draw", gpu.GpuPowerReadings.PowerDraw) + common.SetIfUsed("float", fields, "module_power_draw", gpu.ModulePowerReadings.PowerDraw) + acc.AddFields("nvidia_smi", fields, tags, timestamp) + } + + return nil +} diff --git a/plugins/inputs/nvidia_smi/schema_v12/types.go b/plugins/inputs/nvidia_smi/schema_v12/types.go new file mode 100644 index 000000000..40843e7f6 --- /dev/null +++ b/plugins/inputs/nvidia_smi/schema_v12/types.go @@ -0,0 +1,255 @@ +package schema_v12 + +// Generated by https://github.com/twpayne/go-xmlstruct with some type corrections. +type smi struct { + AttachedGpus string `xml:"attached_gpus"` + CudaVersion string `xml:"cuda_version"` + DriverVersion string `xml:"driver_version"` + Gpu []struct { + ID string `xml:"id,attr"` + AccountedProcesses struct{} `xml:"accounted_processes"` + AccountingMode string `xml:"accounting_mode"` + AccountingModeBufferSize string `xml:"accounting_mode_buffer_size"` + AddressingMode string `xml:"addressing_mode"` + ApplicationsClocks struct { + GraphicsClock string `xml:"graphics_clock"` + MemClock string `xml:"mem_clock"` + } `xml:"applications_clocks"` + Bar1MemoryUsage struct { + Free string `xml:"free"` + Total string `xml:"total"` + Used string `xml:"used"` + } `xml:"bar1_memory_usage"` + BoardID string `xml:"board_id"` + BoardPartNumber string `xml:"board_part_number"` + CcProtectedMemoryUsage struct { + Free string `xml:"free"` + Total string `xml:"total"` + Used string `xml:"used"` + } `xml:"cc_protected_memory_usage"` + ClockPolicy struct { + AutoBoost string `xml:"auto_boost"` + AutoBoostDefault string `xml:"auto_boost_default"` + } `xml:"clock_policy"` + Clocks struct { + GraphicsClock string `xml:"graphics_clock"` + MemClock string `xml:"mem_clock"` + SmClock string `xml:"sm_clock"` + VideoClock string `xml:"video_clock"` + } `xml:"clocks"` + ClocksEventReasons struct { + ClocksEventReasonApplicationsClocksSetting string `xml:"clocks_event_reason_applications_clocks_setting"` + ClocksEventReasonDisplayClocksSetting string `xml:"clocks_event_reason_display_clocks_setting"` + ClocksEventReasonGpuIdle string `xml:"clocks_event_reason_gpu_idle"` + ClocksEventReasonHwPowerBrakeSlowdown string `xml:"clocks_event_reason_hw_power_brake_slowdown"` + ClocksEventReasonHwSlowdown string `xml:"clocks_event_reason_hw_slowdown"` + ClocksEventReasonHwThermalSlowdown string `xml:"clocks_event_reason_hw_thermal_slowdown"` + ClocksEventReasonSwPowerCap string `xml:"clocks_event_reason_sw_power_cap"` + ClocksEventReasonSwThermalSlowdown string `xml:"clocks_event_reason_sw_thermal_slowdown"` + ClocksEventReasonSyncBoost string `xml:"clocks_event_reason_sync_boost"` + } `xml:"clocks_event_reasons"` + ComputeMode string `xml:"compute_mode"` + DefaultApplicationsClocks struct { + GraphicsClock string `xml:"graphics_clock"` + MemClock string `xml:"mem_clock"` + } `xml:"default_applications_clocks"` + DeferredClocks struct { + MemClock string `xml:"mem_clock"` + } `xml:"deferred_clocks"` + DisplayActive string `xml:"display_active"` + DisplayMode string `xml:"display_mode"` + DriverModel struct { + CurrentDm string `xml:"current_dm"` + PendingDm string `xml:"pending_dm"` + } `xml:"driver_model"` + EccErrors struct { + Aggregate struct { + DramCorrectable string `xml:"dram_correctable"` + DramUncorrectable string `xml:"dram_uncorrectable"` + SramCorrectable string `xml:"sram_correctable"` + SramUncorrectable string `xml:"sram_uncorrectable"` + } `xml:"aggregate"` + Volatile struct { + DramCorrectable string `xml:"dram_correctable"` + DramUncorrectable string `xml:"dram_uncorrectable"` + SramCorrectable string `xml:"sram_correctable"` + SramUncorrectable string `xml:"sram_uncorrectable"` + } `xml:"volatile"` + } `xml:"ecc_errors"` + EccMode struct { + CurrentEcc string `xml:"current_ecc"` + PendingEcc string `xml:"pending_ecc"` + } `xml:"ecc_mode"` + EncoderStats struct { + AverageFps string `xml:"average_fps"` + AverageLatency string `xml:"average_latency"` + SessionCount string `xml:"session_count"` + } `xml:"encoder_stats"` + Fabric struct { + State string `xml:"state"` + Status string `xml:"status"` + } `xml:"fabric"` + FanSpeed string `xml:"fan_speed"` + FbMemoryUsage struct { + Free string `xml:"free"` + Reserved string `xml:"reserved"` + Total string `xml:"total"` + Used string `xml:"used"` + } `xml:"fb_memory_usage"` + FbcStats struct { + AverageFps string `xml:"average_fps"` + AverageLatency string `xml:"average_latency"` + SessionCount string `xml:"session_count"` + } `xml:"fbc_stats"` + GpuFruPartNumber string `xml:"gpu_fru_part_number"` + GpuModuleID string `xml:"gpu_module_id"` + GpuOperationMode struct { + CurrentGom string `xml:"current_gom"` + PendingGom string `xml:"pending_gom"` + } `xml:"gpu_operation_mode"` + GpuPartNumber string `xml:"gpu_part_number"` + GpuPowerReadings struct { + CurrentPowerLimit string `xml:"current_power_limit"` + DefaultPowerLimit string `xml:"default_power_limit"` + MaxPowerLimit string `xml:"max_power_limit"` + MinPowerLimit string `xml:"min_power_limit"` + PowerDraw string `xml:"power_draw"` + PowerState string `xml:"power_state"` + RequestedPowerLimit string `xml:"requested_power_limit"` + } `xml:"gpu_power_readings"` + GpuResetStatus struct { + DrainAndResetRecommended string `xml:"drain_and_reset_recommended"` + ResetRequired string `xml:"reset_required"` + } `xml:"gpu_reset_status"` + GpuVirtualizationMode struct { + HostVgpuMode string `xml:"host_vgpu_mode"` + VirtualizationMode string `xml:"virtualization_mode"` + } `xml:"gpu_virtualization_mode"` + GspFirmwareVersion string `xml:"gsp_firmware_version"` + Ibmnpu struct { + RelaxedOrderingMode string `xml:"relaxed_ordering_mode"` + } `xml:"ibmnpu"` + InforomVersion struct { + EccObject string `xml:"ecc_object"` + ImgVersion string `xml:"img_version"` + OemObject string `xml:"oem_object"` + PwrObject string `xml:"pwr_object"` + } `xml:"inforom_version"` + MaxClocks struct { + GraphicsClock string `xml:"graphics_clock"` + MemClock string `xml:"mem_clock"` + SmClock string `xml:"sm_clock"` + VideoClock string `xml:"video_clock"` + } `xml:"max_clocks"` + MaxCustomerBoostClocks struct { + GraphicsClock string `xml:"graphics_clock"` + } `xml:"max_customer_boost_clocks"` + MigDevices string `xml:"mig_devices"` + MigMode struct { + CurrentMig string `xml:"current_mig"` + PendingMig string `xml:"pending_mig"` + } `xml:"mig_mode"` + MinorNumber string `xml:"minor_number"` + ModulePowerReadings struct { + CurrentPowerLimit string `xml:"current_power_limit"` + DefaultPowerLimit string `xml:"default_power_limit"` + MaxPowerLimit string `xml:"max_power_limit"` + MinPowerLimit string `xml:"min_power_limit"` + PowerDraw string `xml:"power_draw"` + PowerState string `xml:"power_state"` + RequestedPowerLimit string `xml:"requested_power_limit"` + } `xml:"module_power_readings"` + MultigpuBoard string `xml:"multigpu_board"` + Pci struct { + AtomicCapsInbound string `xml:"atomic_caps_inbound"` + AtomicCapsOutbound string `xml:"atomic_caps_outbound"` + PciBridgeChip struct { + BridgeChipFw string `xml:"bridge_chip_fw"` + BridgeChipType string `xml:"bridge_chip_type"` + } `xml:"pci_bridge_chip"` + PciBus string `xml:"pci_bus"` + PciBusID string `xml:"pci_bus_id"` + PciDevice string `xml:"pci_device"` + PciDeviceID string `xml:"pci_device_id"` + PciDomain string `xml:"pci_domain"` + PciGpuLinkInfo struct { + LinkWidths struct { + CurrentLinkWidth string `xml:"current_link_width"` + MaxLinkWidth string `xml:"max_link_width"` + } `xml:"link_widths"` + PcieGen struct { + CurrentLinkGen string `xml:"current_link_gen"` + DeviceCurrentLinkGen string `xml:"device_current_link_gen"` + MaxDeviceLinkGen string `xml:"max_device_link_gen"` + MaxHostLinkGen string `xml:"max_host_link_gen"` + MaxLinkGen string `xml:"max_link_gen"` + } `xml:"pcie_gen"` + } `xml:"pci_gpu_link_info"` + PciSubSystemID string `xml:"pci_sub_system_id"` + ReplayCounter string `xml:"replay_counter"` + ReplayRolloverCounter string `xml:"replay_rollover_counter"` + RxUtil string `xml:"rx_util"` + TxUtil string `xml:"tx_util"` + } `xml:"pci"` + PerformanceState string `xml:"performance_state"` + PersistenceMode string `xml:"persistence_mode"` + Processes struct{} `xml:"processes"` + ProductArchitecture string `xml:"product_architecture"` + ProductBrand string `xml:"product_brand"` + ProductName string `xml:"product_name"` + RemappedRows struct { + // Manually added + Correctable string `xml:"remapped_row_corr"` + Uncorrectable string `xml:"remapped_row_unc"` + Pending string `xml:"remapped_row_pending"` + Failure string `xml:"remapped_row_failure"` + } `xml:"remapped_rows"` + RetiredPages struct { + DoubleBitRetirement struct { + RetiredCount string `xml:"retired_count"` + RetiredPagelist string `xml:"retired_pagelist"` + } `xml:"double_bit_retirement"` + MultipleSingleBitRetirement struct { + RetiredCount string `xml:"retired_count"` + RetiredPagelist string `xml:"retired_pagelist"` + } `xml:"multiple_single_bit_retirement"` + PendingBlacklist string `xml:"pending_blacklist"` + PendingRetirement string `xml:"pending_retirement"` + } `xml:"retired_pages"` + Serial string `xml:"serial"` + SupportedClocks struct { + SupportedMemClock []struct { + SupportedGraphicsClock []string `xml:"supported_graphics_clock"` + Value string `xml:"value"` + } `xml:"supported_mem_clock"` + } `xml:"supported_clocks"` + SupportedGpuTargetTemp struct { + GpuTargetTempMax string `xml:"gpu_target_temp_max"` + GpuTargetTempMin string `xml:"gpu_target_temp_min"` + } `xml:"supported_gpu_target_temp"` + Temperature struct { + GpuTargetTemperature string `xml:"gpu_target_temperature"` + GpuTemp string `xml:"gpu_temp"` + GpuTempMaxGpuThreshold string `xml:"gpu_temp_max_gpu_threshold"` + GpuTempMaxMemThreshold string `xml:"gpu_temp_max_mem_threshold"` + GpuTempMaxThreshold string `xml:"gpu_temp_max_threshold"` + GpuTempSlowThreshold string `xml:"gpu_temp_slow_threshold"` + GpuTempTlimit string `xml:"gpu_temp_tlimit"` + MemoryTemp string `xml:"memory_temp"` + } `xml:"temperature"` + Utilization struct { + DecoderUtil string `xml:"decoder_util"` + EncoderUtil string `xml:"encoder_util"` + GpuUtil string `xml:"gpu_util"` + JpegUtil string `xml:"jpeg_util"` + MemoryUtil string `xml:"memory_util"` + OfaUtil string `xml:"ofa_util"` + } `xml:"utilization"` + UUID string `xml:"uuid"` + VbiosVersion string `xml:"vbios_version"` + Voltage struct { + GraphicsVolt string `xml:"graphics_volt"` + } `xml:"voltage"` + } `xml:"gpu"` + Timestamp string `xml:"timestamp"` +} diff --git a/plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml b/plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml new file mode 100644 index 000000000..e427481ca --- /dev/null +++ b/plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml @@ -0,0 +1,786 @@ + + + + Thu Jul 20 17:00:50 2023 + 536.40 + 12.2 + 1 + + NVIDIA GeForce RTX 3080 + GeForce + Ampere + Enabled + Enabled + N/A + N/A + + N/A + N/A + + + None + + Disabled + 4000 + + WDDM + WDDM + + N/A + GPU-19d6d965-2acc-f646-00f8-4c76979aabb4 + N/A + 94.02.71.40.72 + No + 0x400 + N/A + 2216-202-A1 + N/A + 1 + + G001.0000.03.03 + 2.0 + N/A + N/A + + + N/A + N/A + + N/A + + Pass-Through + N/A + + + No + N/A + + + N/A + + + 04 + 00 + 0000 + 221610DE + 00000000:04:00.0 + 161219DA + + + 4 + 4 + 4 + 4 + N/A + + + 16x + 16x + + + + N/A + N/A + + 0 + 0 + 1000 KB/s + 6000 KB/s + N/A + N/A + + 0 % + P8 + + Active + Not Active + Not Active + Not Active + Not Active + Not Active + Not Active + Not Active + Not Active + + + 10240 MiB + 173 MiB + 1128 MiB + 8938 MiB + + + 16384 MiB + 1 MiB + 16383 MiB + + + N/A + N/A + N/A + + Default + + 0 % + 37 % + 0 % + 0 % + 0 % + 0 % + + + 0 + 0 + 0 + + + 0 + 0 + 0 + + + N/A + N/A + + + + N/A + N/A + N/A + N/A + + + N/A + N/A + N/A + N/A + + + + + N/A + N/A + + + N/A + N/A + + N/A + N/A + + N/A + + 31 C + N/A + 98 C + 95 C + 93 C + 91 C + N/A + N/A + + + 65 C + 91 C + + + P8 + 22.78 W + 336.00 W + 336.00 W + 320.00 W + 100.00 W + 336.00 W + + + P8 + N/A + N/A + N/A + N/A + N/A + N/A + + + 210 MHz + 210 MHz + 405 MHz + 555 MHz + + + N/A + N/A + + + N/A + N/A + + + N/A + + + 2100 MHz + 2100 MHz + 9501 MHz + 1950 MHz + + + N/A + + + N/A + N/A + + + 750.000 mV + + + N/A + N/A + + + + 9501 MHz + 2100 MHz + 2085 MHz + 2070 MHz + 2055 MHz + 2040 MHz + 2025 MHz + 2010 MHz + 1995 MHz + 1980 MHz + 1965 MHz + 1950 MHz + 1935 MHz + 1920 MHz + 1905 MHz + 1890 MHz + 1875 MHz + 1860 MHz + 1845 MHz + 1830 MHz + 1815 MHz + 1800 MHz + 1785 MHz + 1770 MHz + 1755 MHz + 1740 MHz + 1725 MHz + 1710 MHz + 1695 MHz + 1680 MHz + 1665 MHz + 1650 MHz + 1635 MHz + 1620 MHz + 1605 MHz + 1590 MHz + 1575 MHz + 1560 MHz + 1545 MHz + 1530 MHz + 1515 MHz + 1500 MHz + 1485 MHz + 1470 MHz + 1455 MHz + 1440 MHz + 1425 MHz + 1410 MHz + 1395 MHz + 1380 MHz + 1365 MHz + 1350 MHz + 1335 MHz + 1320 MHz + 1305 MHz + 1290 MHz + 1275 MHz + 1260 MHz + 1245 MHz + 1230 MHz + 1215 MHz + 1200 MHz + 1185 MHz + 1170 MHz + 1155 MHz + 1140 MHz + 1125 MHz + 1110 MHz + 1095 MHz + 1080 MHz + 1065 MHz + 1050 MHz + 1035 MHz + 1020 MHz + 1005 MHz + 990 MHz + 975 MHz + 960 MHz + 945 MHz + 930 MHz + 915 MHz + 900 MHz + 885 MHz + 870 MHz + 855 MHz + 840 MHz + 825 MHz + 810 MHz + 795 MHz + 780 MHz + 765 MHz + 750 MHz + 735 MHz + 720 MHz + 705 MHz + 690 MHz + 675 MHz + 660 MHz + 645 MHz + 630 MHz + 615 MHz + 600 MHz + 585 MHz + 570 MHz + 555 MHz + 540 MHz + 525 MHz + 510 MHz + 495 MHz + 480 MHz + 465 MHz + 450 MHz + 435 MHz + 420 MHz + 405 MHz + 390 MHz + 375 MHz + 360 MHz + 345 MHz + 330 MHz + 315 MHz + 300 MHz + 285 MHz + 270 MHz + 255 MHz + 240 MHz + 225 MHz + 210 MHz + + + 9251 MHz + 2100 MHz + 2085 MHz + 2070 MHz + 2055 MHz + 2040 MHz + 2025 MHz + 2010 MHz + 1995 MHz + 1980 MHz + 1965 MHz + 1950 MHz + 1935 MHz + 1920 MHz + 1905 MHz + 1890 MHz + 1875 MHz + 1860 MHz + 1845 MHz + 1830 MHz + 1815 MHz + 1800 MHz + 1785 MHz + 1770 MHz + 1755 MHz + 1740 MHz + 1725 MHz + 1710 MHz + 1695 MHz + 1680 MHz + 1665 MHz + 1650 MHz + 1635 MHz + 1620 MHz + 1605 MHz + 1590 MHz + 1575 MHz + 1560 MHz + 1545 MHz + 1530 MHz + 1515 MHz + 1500 MHz + 1485 MHz + 1470 MHz + 1455 MHz + 1440 MHz + 1425 MHz + 1410 MHz + 1395 MHz + 1380 MHz + 1365 MHz + 1350 MHz + 1335 MHz + 1320 MHz + 1305 MHz + 1290 MHz + 1275 MHz + 1260 MHz + 1245 MHz + 1230 MHz + 1215 MHz + 1200 MHz + 1185 MHz + 1170 MHz + 1155 MHz + 1140 MHz + 1125 MHz + 1110 MHz + 1095 MHz + 1080 MHz + 1065 MHz + 1050 MHz + 1035 MHz + 1020 MHz + 1005 MHz + 990 MHz + 975 MHz + 960 MHz + 945 MHz + 930 MHz + 915 MHz + 900 MHz + 885 MHz + 870 MHz + 855 MHz + 840 MHz + 825 MHz + 810 MHz + 795 MHz + 780 MHz + 765 MHz + 750 MHz + 735 MHz + 720 MHz + 705 MHz + 690 MHz + 675 MHz + 660 MHz + 645 MHz + 630 MHz + 615 MHz + 600 MHz + 585 MHz + 570 MHz + 555 MHz + 540 MHz + 525 MHz + 510 MHz + 495 MHz + 480 MHz + 465 MHz + 450 MHz + 435 MHz + 420 MHz + 405 MHz + 390 MHz + 375 MHz + 360 MHz + 345 MHz + 330 MHz + 315 MHz + 300 MHz + 285 MHz + 270 MHz + 255 MHz + 240 MHz + 225 MHz + 210 MHz + + + 5001 MHz + 2100 MHz + 2085 MHz + 2070 MHz + 2055 MHz + 2040 MHz + 2025 MHz + 2010 MHz + 1995 MHz + 1980 MHz + 1965 MHz + 1950 MHz + 1935 MHz + 1920 MHz + 1905 MHz + 1890 MHz + 1875 MHz + 1860 MHz + 1845 MHz + 1830 MHz + 1815 MHz + 1800 MHz + 1785 MHz + 1770 MHz + 1755 MHz + 1740 MHz + 1725 MHz + 1710 MHz + 1695 MHz + 1680 MHz + 1665 MHz + 1650 MHz + 1635 MHz + 1620 MHz + 1605 MHz + 1590 MHz + 1575 MHz + 1560 MHz + 1545 MHz + 1530 MHz + 1515 MHz + 1500 MHz + 1485 MHz + 1470 MHz + 1455 MHz + 1440 MHz + 1425 MHz + 1410 MHz + 1395 MHz + 1380 MHz + 1365 MHz + 1350 MHz + 1335 MHz + 1320 MHz + 1305 MHz + 1290 MHz + 1275 MHz + 1260 MHz + 1245 MHz + 1230 MHz + 1215 MHz + 1200 MHz + 1185 MHz + 1170 MHz + 1155 MHz + 1140 MHz + 1125 MHz + 1110 MHz + 1095 MHz + 1080 MHz + 1065 MHz + 1050 MHz + 1035 MHz + 1020 MHz + 1005 MHz + 990 MHz + 975 MHz + 960 MHz + 945 MHz + 930 MHz + 915 MHz + 900 MHz + 885 MHz + 870 MHz + 855 MHz + 840 MHz + 825 MHz + 810 MHz + 795 MHz + 780 MHz + 765 MHz + 750 MHz + 735 MHz + 720 MHz + 705 MHz + 690 MHz + 675 MHz + 660 MHz + 645 MHz + 630 MHz + 615 MHz + 600 MHz + 585 MHz + 570 MHz + 555 MHz + 540 MHz + 525 MHz + 510 MHz + 495 MHz + 480 MHz + 465 MHz + 450 MHz + 435 MHz + 420 MHz + 405 MHz + 390 MHz + 375 MHz + 360 MHz + 345 MHz + 330 MHz + 315 MHz + 300 MHz + 285 MHz + 270 MHz + 255 MHz + 240 MHz + 225 MHz + 210 MHz + + + 810 MHz + 2100 MHz + 2085 MHz + 2070 MHz + 2055 MHz + 2040 MHz + 2025 MHz + 2010 MHz + 1995 MHz + 1980 MHz + 1965 MHz + 1950 MHz + 1935 MHz + 1920 MHz + 1905 MHz + 1890 MHz + 1875 MHz + 1860 MHz + 1845 MHz + 1830 MHz + 1815 MHz + 1800 MHz + 1785 MHz + 1770 MHz + 1755 MHz + 1740 MHz + 1725 MHz + 1710 MHz + 1695 MHz + 1680 MHz + 1665 MHz + 1650 MHz + 1635 MHz + 1620 MHz + 1605 MHz + 1590 MHz + 1575 MHz + 1560 MHz + 1545 MHz + 1530 MHz + 1515 MHz + 1500 MHz + 1485 MHz + 1470 MHz + 1455 MHz + 1440 MHz + 1425 MHz + 1410 MHz + 1395 MHz + 1380 MHz + 1365 MHz + 1350 MHz + 1335 MHz + 1320 MHz + 1305 MHz + 1290 MHz + 1275 MHz + 1260 MHz + 1245 MHz + 1230 MHz + 1215 MHz + 1200 MHz + 1185 MHz + 1170 MHz + 1155 MHz + 1140 MHz + 1125 MHz + 1110 MHz + 1095 MHz + 1080 MHz + 1065 MHz + 1050 MHz + 1035 MHz + 1020 MHz + 1005 MHz + 990 MHz + 975 MHz + 960 MHz + 945 MHz + 930 MHz + 915 MHz + 900 MHz + 885 MHz + 870 MHz + 855 MHz + 840 MHz + 825 MHz + 810 MHz + 795 MHz + 780 MHz + 765 MHz + 750 MHz + 735 MHz + 720 MHz + 705 MHz + 690 MHz + 675 MHz + 660 MHz + 645 MHz + 630 MHz + 615 MHz + 600 MHz + 585 MHz + 570 MHz + 555 MHz + 540 MHz + 525 MHz + 510 MHz + 495 MHz + 480 MHz + 465 MHz + 450 MHz + 435 MHz + 420 MHz + 405 MHz + 390 MHz + 375 MHz + 360 MHz + 345 MHz + 330 MHz + 315 MHz + 300 MHz + 285 MHz + 270 MHz + 255 MHz + 240 MHz + 225 MHz + 210 MHz + + + 405 MHz + 420 MHz + 405 MHz + 390 MHz + 375 MHz + 360 MHz + 345 MHz + 330 MHz + 315 MHz + 300 MHz + 285 MHz + 270 MHz + 255 MHz + 240 MHz + 225 MHz + 210 MHz + + + + + + + + +