huatuo/core/metrics/memory_cgroup.go

130 lines
3.4 KiB
Go

// Copyright 2025 The HuaTuo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package collector
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"huatuo-bamai/internal/bpf"
"huatuo-bamai/internal/pod"
"huatuo-bamai/internal/utils/bpfutil"
"huatuo-bamai/pkg/metric"
"huatuo-bamai/pkg/tracing"
)
func init() {
tracing.RegisterEventTracing("mmcgroup", newMemoryCgroup)
}
func newMemoryCgroup() (*tracing.EventTracingAttr, error) {
return &tracing.EventTracingAttr{
TracingData: &memoryCgroup{},
Internal: 10,
Flag: tracing.FlagTracing | tracing.FlagMetric,
}, nil
}
type memoryCgroupMetric struct {
DirectstallCount uint64
}
//go:generate $BPF_COMPILE $BPF_INCLUDE -s $BPF_DIR/memory_cgroup.c -o $BPF_DIR/memory_cgroup.o
type memoryCgroup struct {
bpf bpf.BPF
isRuning bool
}
func (c *memoryCgroup) Update() ([]*metric.Data, error) {
if !c.isRuning {
return nil, nil
}
containersMap := make(map[uint64]*pod.Container)
containers, err := pod.GetNormalContainers()
if err != nil {
return nil, fmt.Errorf("Can't get normal container: %w", err)
}
for _, container := range containers {
containersMap[container.CSS["memory"]] = container
}
items, err := c.bpf.DumpMapByName("mem_cgroup_map")
if err != nil {
return nil, fmt.Errorf("Can't dump mem_cgroup_map: %w", err)
}
var (
cgroupMetric memoryCgroupMetric
containersMetric []*metric.Data
css uint64
)
for _, v := range items {
keyBuf := bytes.NewReader(v.Key)
if err := binary.Read(keyBuf, binary.LittleEndian, &css); err != nil {
return nil, fmt.Errorf("mem_cgroup_map key: %w", err)
}
valBuf := bytes.NewReader(v.Value)
if err := binary.Read(valBuf, binary.LittleEndian, &cgroupMetric); err != nil {
return nil, fmt.Errorf("mem_cgroup_map value: %w", err)
}
if container, exist := containersMap[css]; exist {
containersMetric = append(containersMetric,
metric.NewContainerGaugeData(container, "directstallcount",
float64(cgroupMetric.DirectstallCount),
"counting of cgroup try_charge reclaim", nil))
}
}
// if events haven't happened, upload zero for all containers.
if len(items) == 0 {
for _, container := range containersMap {
containersMetric = append(containersMetric,
metric.NewContainerGaugeData(container, "directstallcount", float64(0),
"counting of cgroup try_charge reclaim", nil))
}
}
return containersMetric, nil
}
func (c *memoryCgroup) Start(ctx context.Context) error {
var err error
c.bpf, err = bpf.LoadBpf(bpfutil.ThisBpfOBJ(), nil)
if err != nil {
return fmt.Errorf("LoadBpf memory_cgroup.o: %w", err)
}
defer c.bpf.Close()
if err = c.bpf.Attach(); err != nil {
return fmt.Errorf("failed to Attach, err: %w", err)
}
childCtx, cancel := context.WithCancel(ctx)
defer cancel()
c.bpf.WaitDetachByBreaker(childCtx, cancel)
c.isRuning = true
<-childCtx.Done()
c.isRuning = false
return nil
}