feat: display current CPU frequency on dashboard

Dashboard now shows the active frequency of each CPU core when cpufreq
is available on non-virtualized systems, enhancing real-time accuracy.

Solves the issue of displaying 0MHz on certain SBCs due to
/proc/cpuinfo limitations.

Signed-off-by: Nico Berlee <nico.berlee@on2it.net>
Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Nico Berlee 2024-11-07 13:30:35 +01:00 committed by Andrey Smirnov
parent fbce267aee
commit 11380f933d
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
11 changed files with 2473 additions and 1409 deletions

View File

@ -21,6 +21,7 @@ service MachineService {
rpc Bootstrap(BootstrapRequest) returns (BootstrapResponse);
rpc Containers(ContainersRequest) returns (ContainersResponse);
rpc Copy(CopyRequest) returns (stream common.Data);
rpc CPUFreqStats(google.protobuf.Empty) returns (CPUFreqStatsResponse);
rpc CPUInfo(google.protobuf.Empty) returns (CPUInfoResponse);
rpc DiskStats(google.protobuf.Empty) returns (DiskStatsResponse);
rpc Dmesg(DmesgRequest) returns (stream common.Data);
@ -843,6 +844,24 @@ message SoftIRQStat {
uint64 rcu = 10;
}
// rpc CPUFreqStats
message CPUFreqStatsResponse {
repeated CPUsFreqStats messages = 1;
}
message CPUsFreqStats {
common.Metadata metadata = 1;
repeated CPUFreqStats cpu_freq_stats = 2;
}
message CPUFreqStats {
uint64 current_frequency = 1;
uint64 minimum_frequency = 2;
uint64 maximum_frequency = 3;
string governor = 4;
}
// rpc CPUInfo
message CPUInfoResponse {

View File

@ -12,6 +12,7 @@ import (
"strings"
"github.com/prometheus/procfs"
"github.com/prometheus/procfs/sysfs"
"github.com/siderolabs/gen/maps"
"github.com/siderolabs/gen/xslices"
"google.golang.org/protobuf/types/known/emptypb"
@ -141,6 +142,42 @@ func (s *Server) SystemStat(ctx context.Context, in *emptypb.Empty) (*machine.Sy
return reply, nil
}
// CPUFreqStats implements the machine.MachineServer interface.
func (s *Server) CPUFreqStats(ctx context.Context, in *emptypb.Empty) (*machine.CPUFreqStatsResponse, error) {
fs, err := sysfs.NewDefaultFS()
if err != nil {
return nil, err
}
systemCpufreqStats, err := fs.SystemCpufreq()
if err != nil {
return nil, err
}
translateCPUFreqStats := func(in sysfs.SystemCPUCpufreqStats) *machine.CPUFreqStats {
if in.CpuinfoCurrentFrequency == nil || in.CpuinfoMinimumFrequency == nil || in.CpuinfoMaximumFrequency == nil {
return &machine.CPUFreqStats{}
}
return &machine.CPUFreqStats{
CurrentFrequency: *in.CpuinfoCurrentFrequency,
MinimumFrequency: *in.CpuinfoMinimumFrequency,
MaximumFrequency: *in.CpuinfoMaximumFrequency,
Governor: in.Governor,
}
}
reply := &machine.CPUFreqStatsResponse{
Messages: []*machine.CPUsFreqStats{
{
CpuFreqStats: xslices.Map(systemCpufreqStats, translateCPUFreqStats),
},
},
}
return reply, nil
}
// CPUInfo implements the machine.MachineServer interface.
func (s *Server) CPUInfo(ctx context.Context, in *emptypb.Empty) (*machine.CPUInfoResponse, error) {
fs, err := procfs.NewDefaultFS()

View File

@ -41,6 +41,7 @@ var rules = map[string]role.Set{
"/machine.MachineService/ApplyConfiguration": role.MakeSet(role.Admin),
"/machine.MachineService/Bootstrap": role.MakeSet(role.Admin),
"/machine.MachineService/CPUInfo": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/CPUFreqStats": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/Containers": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/Copy": role.MakeSet(role.Admin),
"/machine.MachineService/DiskStats": role.MakeSet(role.Admin, role.Operator, role.Reader),

View File

@ -0,0 +1,73 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build integration_api
package api
import (
"context"
"time"
"google.golang.org/protobuf/types/known/emptypb"
"github.com/siderolabs/talos/internal/integration/base"
"github.com/siderolabs/talos/pkg/machinery/client"
)
// MonitoringSuite ...
type MonitoringSuite struct {
base.APISuite
ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc
}
// SuiteName ...
func (suite *MonitoringSuite) SuiteName() string {
return "api.MonitoringSuite"
}
// SetupTest ...
func (suite *MonitoringSuite) SetupTest() {
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)
}
// TearDownTest ...
func (suite *MonitoringSuite) TearDownTest() {
if suite.ctxCancel != nil {
suite.ctxCancel()
}
}
// TestMonitoringAPIs tests that monitoring APIs are working.
func (suite *MonitoringSuite) TestMonitoringAPIs() {
node := suite.RandomDiscoveredNodeInternalIP()
nodeCtx := client.WithNode(suite.ctx, node)
_, err := suite.Client.MachineClient.CPUFreqStats(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.CPUInfo(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.DiskStats(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.LoadAvg(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.Memory(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.NetworkDeviceStats(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
_, err = suite.Client.MachineClient.SystemStat(nodeCtx, &emptypb.Empty{})
suite.Require().NoError(err)
}
func init() {
allSuites = append(allSuites, new(MonitoringSuite))
}

View File

@ -13,16 +13,17 @@ import (
// Node represents data gathered from a single node.
type Node struct {
// These fields are directly API responses.
Hostname *machine.Hostname
LoadAvg *machine.LoadAvg
Version *machine.Version
Memory *machine.Memory
SystemStat *machine.SystemStat
CPUsInfo *machine.CPUsInfo
NetDevStats *machine.NetworkDeviceStats
DiskStats *machine.DiskStats
Processes *machine.Process
ServiceList *machine.ServiceList
Hostname *machine.Hostname
LoadAvg *machine.LoadAvg
Version *machine.Version
Memory *machine.Memory
SystemStat *machine.SystemStat
CPUsFreqStats *machine.CPUsFreqStats
CPUsInfo *machine.CPUsInfo
NetDevStats *machine.NetworkDeviceStats
DiskStats *machine.DiskStats
Processes *machine.Process
ServiceList *machine.ServiceList
// These fields are calculated as diff with Node data from previous pol.
SystemStatDiff *machine.SystemStat

View File

@ -179,6 +179,27 @@ func (source *Source) gather() *Data {
return nil
},
func() error {
resp, err := source.MachineClient.CPUFreqStats(source.ctx, &emptypb.Empty{})
if err != nil {
return err
}
resultLock.Lock()
defer resultLock.Unlock()
for _, msg := range resp.GetMessages() {
node := source.node(msg)
if _, ok := result.Nodes[node]; !ok {
result.Nodes[node] = &Node{}
}
result.Nodes[node].CPUsFreqStats = msg
}
return nil
},
func() error {
resp, err := source.MachineClient.CPUInfo(source.ctx, &emptypb.Empty{})
if err != nil {

View File

@ -7,6 +7,7 @@ package components
import (
"fmt"
"math"
"sort"
"strconv"
"time"
@ -24,7 +25,6 @@ type headerData struct {
hostname string
version string
uptime string
numCPUs string
cpuFreq string
totalMem string
numProcesses string
@ -107,11 +107,10 @@ func (widget *Header) redraw() {
data := widget.getOrCreateNodeData(widget.selectedNode)
text := fmt.Sprintf(
"[yellow::b]%s[-:-:-] (%s): uptime %s, %sx%s, %s RAM, PROCS %s, CPU %s, RAM %s",
"[yellow::b]%s[-:-:-] (%s): uptime %s, %s, %s RAM, PROCS %s, CPU %s, RAM %s",
data.hostname,
data.version,
data.uptime,
data.numCPUs,
data.cpuFreq,
data.totalMem,
data.numProcesses,
@ -122,6 +121,7 @@ func (widget *Header) redraw() {
widget.SetText(text)
}
//nolint:gocyclo
func (widget *Header) updateNodeAPIData(node string, data *apidata.Node) {
nodeData := widget.getOrCreateNodeData(node)
@ -147,13 +147,46 @@ func (widget *Header) updateNodeAPIData(node string, data *apidata.Node) {
if data.CPUsInfo != nil {
numCPUs := len(data.CPUsInfo.GetCpuInfo())
nodeData.numCPUs = strconv.Itoa(numCPUs)
if numCPUs > 0 {
nodeData.cpuFreq = fmt.Sprintf("%dx%s", numCPUs, widget.humanizeCPUFrequency(data.CPUsInfo.GetCpuInfo()[0].GetCpuMhz()))
} else {
nodeData.cpuFreq = widget.humanizeCPUFrequency(data.CPUsInfo.GetCpuInfo()[0].GetCpuMhz())
}
}
if data.CPUsFreqStats != nil && data.CPUsFreqStats.CpuFreqStats != nil {
numCPUs := len(data.CPUsFreqStats.CpuFreqStats)
uniqMhz := make(map[uint64]int, numCPUs)
for _, cpuFreqStat := range data.CPUsFreqStats.CpuFreqStats {
uniqMhz[cpuFreqStat.CurrentFrequency]++
}
keys := make([]uint64, 0, len(uniqMhz))
for mhz := range uniqMhz {
if mhz == 0 {
continue
}
keys = append(keys, mhz)
}
if len(keys) > 0 {
sort.Slice(keys, func(i, j int) bool { return keys[i] > keys[j] })
nodeData.cpuFreq = ""
}
for i, mhz := range keys {
if i > 0 {
nodeData.cpuFreq += " "
}
nodeData.cpuFreq += fmt.Sprintf("%dx%s", uniqMhz[mhz], widget.humanizeCPUFrequency(float64(mhz)/1000.0))
}
}
if data.Processes != nil {
nodeData.numProcesses = strconv.Itoa(len(data.Processes.GetProcesses()))
}
@ -170,7 +203,6 @@ func (widget *Header) getOrCreateNodeData(node string) *headerData {
hostname: notAvailable,
version: notAvailable,
uptime: notAvailable,
numCPUs: notAvailable,
cpuFreq: notAvailable,
totalMem: notAvailable,
numProcesses: notAvailable,

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@ const (
MachineService_Bootstrap_FullMethodName = "/machine.MachineService/Bootstrap"
MachineService_Containers_FullMethodName = "/machine.MachineService/Containers"
MachineService_Copy_FullMethodName = "/machine.MachineService/Copy"
MachineService_CPUFreqStats_FullMethodName = "/machine.MachineService/CPUFreqStats"
MachineService_CPUInfo_FullMethodName = "/machine.MachineService/CPUInfo"
MachineService_DiskStats_FullMethodName = "/machine.MachineService/DiskStats"
MachineService_Dmesg_FullMethodName = "/machine.MachineService/Dmesg"
@ -90,6 +91,7 @@ type MachineServiceClient interface {
Bootstrap(ctx context.Context, in *BootstrapRequest, opts ...grpc.CallOption) (*BootstrapResponse, error)
Containers(ctx context.Context, in *ContainersRequest, opts ...grpc.CallOption) (*ContainersResponse, error)
Copy(ctx context.Context, in *CopyRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)
CPUFreqStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUFreqStatsResponse, error)
CPUInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUInfoResponse, error)
DiskStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DiskStatsResponse, error)
Dmesg(ctx context.Context, in *DmesgRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)
@ -222,6 +224,16 @@ func (c *machineServiceClient) Copy(ctx context.Context, in *CopyRequest, opts .
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MachineService_CopyClient = grpc.ServerStreamingClient[common.Data]
func (c *machineServiceClient) CPUFreqStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUFreqStatsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CPUFreqStatsResponse)
err := c.cc.Invoke(ctx, MachineService_CPUFreqStats_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *machineServiceClient) CPUInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUInfoResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CPUInfoResponse)
@ -799,6 +811,7 @@ type MachineServiceServer interface {
Bootstrap(context.Context, *BootstrapRequest) (*BootstrapResponse, error)
Containers(context.Context, *ContainersRequest) (*ContainersResponse, error)
Copy(*CopyRequest, grpc.ServerStreamingServer[common.Data]) error
CPUFreqStats(context.Context, *emptypb.Empty) (*CPUFreqStatsResponse, error)
CPUInfo(context.Context, *emptypb.Empty) (*CPUInfoResponse, error)
DiskStats(context.Context, *emptypb.Empty) (*DiskStatsResponse, error)
Dmesg(*DmesgRequest, grpc.ServerStreamingServer[common.Data]) error
@ -894,6 +907,9 @@ func (UnimplementedMachineServiceServer) Containers(context.Context, *Containers
func (UnimplementedMachineServiceServer) Copy(*CopyRequest, grpc.ServerStreamingServer[common.Data]) error {
return status.Errorf(codes.Unimplemented, "method Copy not implemented")
}
func (UnimplementedMachineServiceServer) CPUFreqStats(context.Context, *emptypb.Empty) (*CPUFreqStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CPUFreqStats not implemented")
}
func (UnimplementedMachineServiceServer) CPUInfo(context.Context, *emptypb.Empty) (*CPUInfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CPUInfo not implemented")
}
@ -1121,6 +1137,24 @@ func _MachineService_Copy_Handler(srv interface{}, stream grpc.ServerStream) err
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MachineService_CopyServer = grpc.ServerStreamingServer[common.Data]
func _MachineService_CPUFreqStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MachineServiceServer).CPUFreqStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MachineService_CPUFreqStats_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MachineServiceServer).CPUFreqStats(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _MachineService_CPUInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
@ -1905,6 +1939,10 @@ var MachineService_ServiceDesc = grpc.ServiceDesc{
MethodName: "Containers",
Handler: _MachineService_Containers_Handler,
},
{
MethodName: "CPUFreqStats",
Handler: _MachineService_CPUFreqStats_Handler,
},
{
MethodName: "CPUInfo",
Handler: _MachineService_CPUInfo_Handler,

View File

@ -5751,6 +5751,173 @@ func (m *SoftIRQStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *CPUFreqStatsResponse) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CPUFreqStatsResponse) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *CPUFreqStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Messages) > 0 {
for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *CPUsFreqStats) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CPUsFreqStats) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *CPUsFreqStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.CpuFreqStats) > 0 {
for iNdEx := len(m.CpuFreqStats) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.CpuFreqStats[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x12
}
}
if m.Metadata != nil {
if vtmsg, ok := interface{}(m.Metadata).(interface {
MarshalToSizedBufferVT([]byte) (int, error)
}); ok {
size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
} else {
encoded, err := proto.Marshal(m.Metadata)
if err != nil {
return 0, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *CPUFreqStats) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CPUFreqStats) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *CPUFreqStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Governor) > 0 {
i -= len(m.Governor)
copy(dAtA[i:], m.Governor)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Governor)))
i--
dAtA[i] = 0x22
}
if m.MaximumFrequency != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaximumFrequency))
i--
dAtA[i] = 0x18
}
if m.MinimumFrequency != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinimumFrequency))
i--
dAtA[i] = 0x10
}
if m.CurrentFrequency != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentFrequency))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *CPUInfoResponse) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
@ -12472,6 +12639,71 @@ func (m *SoftIRQStat) SizeVT() (n int) {
return n
}
func (m *CPUFreqStatsResponse) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Messages) > 0 {
for _, e := range m.Messages {
l = e.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
n += len(m.unknownFields)
return n
}
func (m *CPUsFreqStats) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Metadata != nil {
if size, ok := interface{}(m.Metadata).(interface {
SizeVT() int
}); ok {
l = size.SizeVT()
} else {
l = proto.Size(m.Metadata)
}
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if len(m.CpuFreqStats) > 0 {
for _, e := range m.CpuFreqStats {
l = e.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
n += len(m.unknownFields)
return n
}
func (m *CPUFreqStats) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.CurrentFrequency != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentFrequency))
}
if m.MinimumFrequency != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.MinimumFrequency))
}
if m.MaximumFrequency != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.MaximumFrequency))
}
l = len(m.Governor)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *CPUInfoResponse) SizeVT() (n int) {
if m == nil {
return 0
@ -27162,6 +27394,360 @@ func (m *SoftIRQStat) UnmarshalVT(dAtA []byte) error {
}
return nil
}
func (m *CPUFreqStatsResponse) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CPUFreqStatsResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CPUFreqStatsResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Messages = append(m.Messages, &CPUsFreqStats{})
if err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *CPUsFreqStats) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CPUsFreqStats: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CPUsFreqStats: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Metadata == nil {
m.Metadata = &common.Metadata{}
}
if unmarshal, ok := interface{}(m.Metadata).(interface {
UnmarshalVT([]byte) error
}); ok {
if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
} else {
if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {
return err
}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CpuFreqStats", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CpuFreqStats = append(m.CpuFreqStats, &CPUFreqStats{})
if err := m.CpuFreqStats[len(m.CpuFreqStats)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *CPUFreqStats) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CPUFreqStats: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CPUFreqStats: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field CurrentFrequency", wireType)
}
m.CurrentFrequency = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.CurrentFrequency |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MinimumFrequency", wireType)
}
m.MinimumFrequency = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.MinimumFrequency |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MaximumFrequency", wireType)
}
m.MaximumFrequency = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.MaximumFrequency |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Governor", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Governor = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *CPUInfoResponse) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0

View File

@ -304,9 +304,12 @@ description: Talos gRPC API reference.
- [BootstrapRequest](#machine.BootstrapRequest)
- [BootstrapResponse](#machine.BootstrapResponse)
- [CNIConfig](#machine.CNIConfig)
- [CPUFreqStats](#machine.CPUFreqStats)
- [CPUFreqStatsResponse](#machine.CPUFreqStatsResponse)
- [CPUInfo](#machine.CPUInfo)
- [CPUInfoResponse](#machine.CPUInfoResponse)
- [CPUStat](#machine.CPUStat)
- [CPUsFreqStats](#machine.CPUsFreqStats)
- [CPUsInfo](#machine.CPUsInfo)
- [ClusterConfig](#machine.ClusterConfig)
- [ClusterNetworkConfig](#machine.ClusterNetworkConfig)
@ -5352,6 +5355,39 @@ rpc Bootstrap
<a name="machine.CPUFreqStats"></a>
### CPUFreqStats
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| current_frequency | [uint64](#uint64) | | |
| minimum_frequency | [uint64](#uint64) | | |
| maximum_frequency | [uint64](#uint64) | | |
| governor | [string](#string) | | |
<a name="machine.CPUFreqStatsResponse"></a>
### CPUFreqStatsResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| messages | [CPUsFreqStats](#machine.CPUsFreqStats) | repeated | |
<a name="machine.CPUInfo"></a>
### CPUInfo
@ -5431,6 +5467,22 @@ rpc Bootstrap
<a name="machine.CPUsFreqStats"></a>
### CPUsFreqStats
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| metadata | [common.Metadata](#common.Metadata) | | |
| cpu_freq_stats | [CPUFreqStats](#machine.CPUFreqStats) | repeated | |
<a name="machine.CPUsInfo"></a>
### CPUsInfo
@ -8316,6 +8368,7 @@ The machine service definition.
| Bootstrap | [BootstrapRequest](#machine.BootstrapRequest) | [BootstrapResponse](#machine.BootstrapResponse) | Bootstrap method makes control plane node enter etcd bootstrap mode. Node aborts etcd join sequence and creates single-node etcd cluster. If recover_etcd argument is specified, etcd is recovered from a snapshot uploaded with EtcdRecover. |
| Containers | [ContainersRequest](#machine.ContainersRequest) | [ContainersResponse](#machine.ContainersResponse) | |
| Copy | [CopyRequest](#machine.CopyRequest) | [.common.Data](#common.Data) stream | |
| CPUFreqStats | [.google.protobuf.Empty](#google.protobuf.Empty) | [CPUFreqStatsResponse](#machine.CPUFreqStatsResponse) | |
| CPUInfo | [.google.protobuf.Empty](#google.protobuf.Empty) | [CPUInfoResponse](#machine.CPUInfoResponse) | |
| DiskStats | [.google.protobuf.Empty](#google.protobuf.Empty) | [DiskStatsResponse](#machine.DiskStatsResponse) | |
| Dmesg | [DmesgRequest](#machine.DmesgRequest) | [.common.Data](#common.Data) stream | |