diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index 90583b2192..f0ac7ebac4 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -1987,34 +1987,34 @@ node_ipvs_outgoing_packets_total 0 # HELP node_kernel_hung_tasks_total Total number of tasks that have been detected as hung since the system booted. # TYPE node_kernel_hung_tasks_total counter node_kernel_hung_tasks_total 42 -# HELP node_ksmd_full_scans_total ksmd 'full_scans' file. +# HELP node_ksmd_full_scans_total How many times all mergeable areas have been scanned. # TYPE node_ksmd_full_scans_total counter node_ksmd_full_scans_total 323 -# HELP node_ksmd_general_profit_bytes ksmd 'general_profit' file. +# HELP node_ksmd_general_profit_bytes How effective is KSM. ksm_saved_pages * sizeof(page) - (all_rmap_items) * sizeof(rmap_item) # TYPE node_ksmd_general_profit_bytes gauge node_ksmd_general_profit_bytes 1.04448e+06 -# HELP node_ksmd_merge_across_nodes ksmd 'merge_across_nodes' file. +# HELP node_ksmd_merge_across_nodes Specifies if pages from different NUMA nodes can be merged. # TYPE node_ksmd_merge_across_nodes gauge node_ksmd_merge_across_nodes 1 -# HELP node_ksmd_pages_shared ksmd 'pages_shared' file. +# HELP node_ksmd_pages_shared How many shared pages are being used. # TYPE node_ksmd_pages_shared gauge node_ksmd_pages_shared 1 -# HELP node_ksmd_pages_sharing ksmd 'pages_sharing' file. +# HELP node_ksmd_pages_sharing How many more sites are sharing them i.e. how much saved. # TYPE node_ksmd_pages_sharing gauge node_ksmd_pages_sharing 255 -# HELP node_ksmd_pages_to_scan ksmd 'pages_to_scan' file. +# HELP node_ksmd_pages_to_scan How many pages to scan before ksmd goes to sleep. # TYPE node_ksmd_pages_to_scan gauge node_ksmd_pages_to_scan 100 -# HELP node_ksmd_pages_unshared ksmd 'pages_unshared' file. +# HELP node_ksmd_pages_unshared How many pages unique but repeatedly checked for merging. # TYPE node_ksmd_pages_unshared gauge node_ksmd_pages_unshared 0 -# HELP node_ksmd_pages_volatile ksmd 'pages_volatile' file. +# HELP node_ksmd_pages_volatile How many pages changing too fast to be placed in a tree. # TYPE node_ksmd_pages_volatile gauge node_ksmd_pages_volatile 0 -# HELP node_ksmd_run ksmd 'run' file. +# HELP node_ksmd_run The status of ksmd. stopped = 0, running = 1 # TYPE node_ksmd_run gauge node_ksmd_run 1 -# HELP node_ksmd_sleep_seconds ksmd 'sleep_millisecs' file. +# HELP node_ksmd_sleep_seconds How many seconds ksmd should sleep before next scan. # TYPE node_ksmd_sleep_seconds gauge node_ksmd_sleep_seconds 0.02 # HELP node_lnstat_allocs_total linux network cache stats diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index d0656919cd..9afd903d6f 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2019,34 +2019,34 @@ node_ipvs_outgoing_packets_total 0 # HELP node_kernel_hung_tasks_total Total number of tasks that have been detected as hung since the system booted. # TYPE node_kernel_hung_tasks_total counter node_kernel_hung_tasks_total 42 -# HELP node_ksmd_full_scans_total ksmd 'full_scans' file. +# HELP node_ksmd_full_scans_total How many times all mergeable areas have been scanned. # TYPE node_ksmd_full_scans_total counter node_ksmd_full_scans_total 323 -# HELP node_ksmd_general_profit_bytes ksmd 'general_profit' file. +# HELP node_ksmd_general_profit_bytes How effective is KSM. ksm_saved_pages * sizeof(page) - (all_rmap_items) * sizeof(rmap_item) # TYPE node_ksmd_general_profit_bytes gauge node_ksmd_general_profit_bytes 1.04448e+06 -# HELP node_ksmd_merge_across_nodes ksmd 'merge_across_nodes' file. +# HELP node_ksmd_merge_across_nodes Specifies if pages from different NUMA nodes can be merged. # TYPE node_ksmd_merge_across_nodes gauge node_ksmd_merge_across_nodes 1 -# HELP node_ksmd_pages_shared ksmd 'pages_shared' file. +# HELP node_ksmd_pages_shared How many shared pages are being used. # TYPE node_ksmd_pages_shared gauge node_ksmd_pages_shared 1 -# HELP node_ksmd_pages_sharing ksmd 'pages_sharing' file. +# HELP node_ksmd_pages_sharing How many more sites are sharing them i.e. how much saved. # TYPE node_ksmd_pages_sharing gauge node_ksmd_pages_sharing 255 -# HELP node_ksmd_pages_to_scan ksmd 'pages_to_scan' file. +# HELP node_ksmd_pages_to_scan How many pages to scan before ksmd goes to sleep. # TYPE node_ksmd_pages_to_scan gauge node_ksmd_pages_to_scan 100 -# HELP node_ksmd_pages_unshared ksmd 'pages_unshared' file. +# HELP node_ksmd_pages_unshared How many pages unique but repeatedly checked for merging. # TYPE node_ksmd_pages_unshared gauge node_ksmd_pages_unshared 0 -# HELP node_ksmd_pages_volatile ksmd 'pages_volatile' file. +# HELP node_ksmd_pages_volatile How many pages changing too fast to be placed in a tree. # TYPE node_ksmd_pages_volatile gauge node_ksmd_pages_volatile 0 -# HELP node_ksmd_run ksmd 'run' file. +# HELP node_ksmd_run The status of ksmd. stopped = 0, running = 1 # TYPE node_ksmd_run gauge node_ksmd_run 1 -# HELP node_ksmd_sleep_seconds ksmd 'sleep_millisecs' file. +# HELP node_ksmd_sleep_seconds How many seconds ksmd should sleep before next scan. # TYPE node_ksmd_sleep_seconds gauge node_ksmd_sleep_seconds 0.02 # HELP node_lnstat_allocs_total linux network cache stats diff --git a/collector/ksmd_linux.go b/collector/ksmd_linux.go index aeb1a1e8eb..f400f0a0fc 100644 --- a/collector/ksmd_linux.go +++ b/collector/ksmd_linux.go @@ -1,4 +1,4 @@ -// Copyright 2015 The Prometheus Authors +// Copyright The Prometheus 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 @@ -17,7 +17,6 @@ package collector import ( "errors" - "fmt" "log/slog" "os" "path/filepath" @@ -25,45 +24,86 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const ksmdCollectorSubsystem = "ksmd" + var ( - ksmdFiles = []string{"full_scans", "general_profit", "merge_across_nodes", "pages_shared", - "pages_sharing", "pages_to_scan", "pages_unshared", "pages_volatile", "run", - "sleep_millisecs"} + ksmdFiles = []string{ + "full_scans", + "general_profit", + "merge_across_nodes", + "pages_shared", + "pages_sharing", + "pages_to_scan", + "pages_unshared", + "pages_volatile", + "run", + "sleep_millisecs", + } + + // Help text from https://docs.kernel.org/admin-guide/mm/ksm.html + ksmdFullScansDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "full_scans_total"), + "How many times all mergeable areas have been scanned.", + nil, nil, + ) + ksmdGeneralProfitDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "general_profit_bytes"), + "How effective is KSM. ksm_saved_pages * sizeof(page) - (all_rmap_items) * sizeof(rmap_item)", + nil, nil, + ) + ksmdMergeAcrossNodesDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "merge_across_nodes"), + "Specifies if pages from different NUMA nodes can be merged.", + nil, nil, + ) + ksmdPagesSharedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "pages_shared"), + "How many shared pages are being used.", + nil, nil, + ) + ksmdPagesSharingDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "pages_sharing"), + "How many more sites are sharing them i.e. how much saved.", + nil, nil, + ) + ksmdPagesToScanDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "pages_to_scan"), + "How many pages to scan before ksmd goes to sleep.", + nil, nil, + ) + ksmdPagesUnsharedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "pages_unshared"), + "How many pages unique but repeatedly checked for merging.", + nil, nil, + ) + ksmdPagesVolatileDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "pages_volatile"), + "How many pages changing too fast to be placed in a tree.", + nil, nil, + ) + ksmdRunDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "run"), + "The status of ksmd. stopped = 0, running = 1", + nil, nil, + ) + ksmdSleepSecondsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, ksmdCollectorSubsystem, "sleep_seconds"), + "How many seconds ksmd should sleep before next scan.", + nil, nil, + ) ) type ksmdCollector struct { - metricDescs map[string]*prometheus.Desc - logger *slog.Logger + logger *slog.Logger } func init() { - registerCollector("ksmd", defaultDisabled, NewKsmdCollector) -} - -func getCanonicalMetricName(filename string) string { - switch filename { - case "full_scans": - return filename + "_total" - case "general_profit": - return "general_profit_bytes" - case "sleep_millisecs": - return "sleep_seconds" - default: - return filename - } + registerCollector(ksmdCollectorSubsystem, defaultDisabled, NewKsmdCollector) } // NewKsmdCollector returns a new Collector exposing kernel/system statistics. func NewKsmdCollector(logger *slog.Logger) (Collector, error) { - subsystem := "ksmd" - descs := make(map[string]*prometheus.Desc) - - for _, n := range ksmdFiles { - descs[n] = prometheus.NewDesc( - prometheus.BuildFQName(namespace, subsystem, getCanonicalMetricName(n)), - fmt.Sprintf("ksmd '%s' file.", n), nil, nil) - } - return &ksmdCollector{descs, logger}, nil + return &ksmdCollector{logger: logger}, nil } // Update implements Collector and exposes kernel and system statistics. @@ -78,15 +118,29 @@ func (c *ksmdCollector) Update(ch chan<- prometheus.Metric) error { return err } - t := prometheus.GaugeValue v := float64(val) switch n { case "full_scans": - t = prometheus.CounterValue + ch <- prometheus.MustNewConstMetric(ksmdFullScansDesc, prometheus.CounterValue, v) + case "general_profit": + ch <- prometheus.MustNewConstMetric(ksmdGeneralProfitDesc, prometheus.GaugeValue, v) + case "merge_across_nodes": + ch <- prometheus.MustNewConstMetric(ksmdMergeAcrossNodesDesc, prometheus.GaugeValue, v) + case "pages_shared": + ch <- prometheus.MustNewConstMetric(ksmdPagesSharedDesc, prometheus.GaugeValue, v) + case "pages_sharing": + ch <- prometheus.MustNewConstMetric(ksmdPagesSharingDesc, prometheus.GaugeValue, v) + case "pages_to_scan": + ch <- prometheus.MustNewConstMetric(ksmdPagesToScanDesc, prometheus.GaugeValue, v) + case "pages_unshared": + ch <- prometheus.MustNewConstMetric(ksmdPagesUnsharedDesc, prometheus.GaugeValue, v) + case "pages_volatile": + ch <- prometheus.MustNewConstMetric(ksmdPagesVolatileDesc, prometheus.GaugeValue, v) + case "run": + ch <- prometheus.MustNewConstMetric(ksmdRunDesc, prometheus.GaugeValue, v) case "sleep_millisecs": - v /= 1000 + ch <- prometheus.MustNewConstMetric(ksmdSleepSecondsDesc, prometheus.GaugeValue, v/1000) } - ch <- prometheus.MustNewConstMetric(c.metricDescs[n], t, v) } return nil