diff --git a/prometheus/native.c b/prometheus/native.c new file mode 100644 index 000000000..74b2e9a9f --- /dev/null +++ b/prometheus/native.c @@ -0,0 +1,60 @@ +//go:build ignore || (darwin && cgo) + +#include +#include +// Compiler warns shared_memory_server.h is deprecated, use this instead. +// But this doesn't define SHARED_XXX_REGION_SIZE. +//#include +#include // SHARED_DATA_REGION_SIZE, SHARED_TEXT_REGION_SIZE +#include +#include + +int getmem (unsigned long long *rss, unsigned long long *vs) +{ + // https://github.com/apple-oss-distributions/adv_cmds/blob/8744084ea0ff41ca4bb96b0f9c22407d0e48e9b7/ps/tasks.c#L109 + + kern_return_t error; + task_t task = MACH_PORT_NULL; + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + error = task_info(mach_task_self(), + TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); + + if( error != KERN_SUCCESS ) + { + return error; + } + + *rss = t_info.resident_size; + *vs = t_info.virtual_size; + + { + vm_region_basic_info_data_64_t b_info; + mach_vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; + mach_vm_size_t size; + mach_port_t object_name; + + /* + * try to determine if this task has the split libraries + * mapped in... if so, adjust its virtual size down by + * the 2 segments that are used for split libraries + */ + t_info_count = VM_REGION_BASIC_INFO_COUNT_64; + error = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&b_info, &t_info_count, &object_name); + + if (error == KERN_SUCCESS) { + if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && + *vs > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) { + *vs -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); + } + } + } + + // `ps -o rss,vsize,command` prints values in KB + printf("rss is %qd (%qd KB)\n", *rss, (unsigned long long) (*rss / 1024)); + printf("vs is %qd (%qd KB)\n", *vs, (unsigned long long) (*vs / 1024)); + + return 0; +} diff --git a/prometheus/process_collector.go b/prometheus/process_collector.go index 62a4e7ad9..f39d1e722 100644 --- a/prometheus/process_collector.go +++ b/prometheus/process_collector.go @@ -33,6 +33,14 @@ type processCollector struct { inBytes, outBytes *Desc } +func init() { + // Debugging to show the correct implementation is used based on CGO_ENABLED=0. + if rss, vs, err := getMemory(); err == nil { + fmt.Printf("GO: rss -> %d\n", rss) + fmt.Printf("GO: vs -> %d\n", vs) + } +} + // ProcessCollectorOpts defines the behavior of a process metrics collector // created with NewProcessCollector. type ProcessCollectorOpts struct { diff --git a/prometheus/process_collector_darwin.go b/prometheus/process_collector_darwin.go index 4d9314c3d..c4067acee 100644 --- a/prometheus/process_collector_darwin.go +++ b/prometheus/process_collector_darwin.go @@ -85,7 +85,18 @@ func (c *processCollector) processCollect(ch chan<- Metric) { c.reportError(ch, c.cpuTotal, err) } - // TODO: publish c.vsize and c.rss values + if rss, vs, err := getMemory(); err == nil { + if rss != 0 { + ch <- MustNewConstMetric(c.rss, GaugeValue, float64(rss)) + } + + if vs != 0 { + ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(vs)) + } + } else { + c.reportError(ch, c.rss, err) + c.reportError(ch, c.vsize, err) + } if fds, err := getOpenFileCount(); err == nil { ch <- MustNewConstMetric(c.openFDs, GaugeValue, fds) diff --git a/prometheus/process_collector_memory.go b/prometheus/process_collector_memory.go new file mode 100644 index 000000000..79a2926a8 --- /dev/null +++ b/prometheus/process_collector_memory.go @@ -0,0 +1,34 @@ +// Copyright 2024 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 +// +// 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. + +//go:build darwin && cgo + +package prometheus + +/* +int getmem(unsigned long long *rss, unsigned long long *vs); +*/ +import "C" +import "fmt" + +func getMemory() (uint64, uint64, error) { + var ( + rss, vs C.ulonglong + ) + + if err := C.getmem(&rss, &vs); err != 0 { + return 0, 0, fmt.Errorf("task_info() failed with 0x%x", int(err)) + } + + return uint64(rss), uint64(vs), nil +} diff --git a/prometheus/prometheus_collector_memory_noop.go b/prometheus/prometheus_collector_memory_noop.go new file mode 100644 index 000000000..853cd9d8b --- /dev/null +++ b/prometheus/prometheus_collector_memory_noop.go @@ -0,0 +1,20 @@ +// Copyright 2024 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 +// +// 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. + +//go:build !darwin || !cgo + +package prometheus + +func getMemory() (uint64, uint64, error) { + return 0, 0, nil +}