get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/pse/pse_freebsd_amd64.go (about)

     1  // Copyright 2015-2020 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // This is the amd64-specific FreeBSD implementation, with hard-coded offset
    15  // constants derived by running freebsd.txt; having this implementation allows
    16  // us to compile without CGO, which lets us cross-compile for FreeBSD from our
    17  // CI system and so supply binaries for FreeBSD amd64.
    18  //
    19  // To generate for other architectures:
    20  //   1. Update pse_freebsd.go, change the build exclusion to exclude your arch
    21  //   2. Copy this file to be built for your arch
    22  //   3. Update `nativeEndian` below
    23  //   4. Link `freebsd.txt` to have a .c filename and compile and run, then
    24  //      paste the outputs into the const section below.
    25  
    26  package pse
    27  
    28  import (
    29  	"encoding/binary"
    30  	"syscall"
    31  
    32  	"golang.org/x/sys/unix"
    33  )
    34  
    35  // On FreeBSD, to get proc information we read it out of the kernel using a
    36  // binary sysctl.  The endianness of integers is thus explicitly "host", rather
    37  // than little or big endian.
    38  var nativeEndian = binary.LittleEndian
    39  
    40  const (
    41  	KIP_OFF_size   = 256
    42  	KIP_OFF_rssize = 264
    43  	KIP_OFF_pctcpu = 308
    44  )
    45  
    46  var pageshift int
    47  
    48  func init() {
    49  	// To get the physical page size, the C library checks two places:
    50  	//   process ELF auxiliary info, AT_PAGESZ
    51  	//   as a fallback, the hw.pagesize sysctl
    52  	// In looking closely, I found that the Go runtime support is handling
    53  	// this for us, and exposing that as syscall.Getpagesize, having checked
    54  	// both in the same ways, at process start, so a call to that should return
    55  	// a memory value without even a syscall bounce.
    56  	pagesize := syscall.Getpagesize()
    57  	pageshift = 0
    58  	for pagesize > 1 {
    59  		pageshift += 1
    60  		pagesize >>= 1
    61  	}
    62  }
    63  
    64  func ProcUsage(pcpu *float64, rss, vss *int64) error {
    65  	rawdata, err := unix.SysctlRaw("kern.proc.pid", unix.Getpid())
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	r_vss_bytes := nativeEndian.Uint32(rawdata[KIP_OFF_size:])
    71  	r_rss_pages := nativeEndian.Uint32(rawdata[KIP_OFF_rssize:])
    72  	rss_bytes := r_rss_pages << pageshift
    73  
    74  	// In C: fixpt_t ki_pctcpu
    75  	// Doc: %cpu for process during ki_swtime
    76  	// fixpt_t is __uint32_t
    77  	// usr.bin/top uses pctdouble to convert to a double (float64)
    78  	// define pctdouble(p) ((double)(p) / FIXED_PCTCPU)
    79  	// FIXED_PCTCPU is _usually_ FSCALE (some architectures are special)
    80  	// <sys/param.h> has:
    81  	//   #define FSHIFT  11              /* bits to right of fixed binary point */
    82  	//   #define FSCALE  (1<<FSHIFT)
    83  	r_pcpu := nativeEndian.Uint32(rawdata[KIP_OFF_pctcpu:])
    84  	f_pcpu := float64(r_pcpu) / float64(2048)
    85  
    86  	*rss = int64(rss_bytes)
    87  	*vss = int64(r_vss_bytes)
    88  	*pcpu = f_pcpu
    89  
    90  	return nil
    91  }