github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/sys/sys_test.go (about)

     1  // Package sys provides methods to read system information
     2  /*
     3   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package sys_test
     6  
     7  // Do not import the main 'tools' package because of circular dependency
     8  // Use t.Logf or t.Errorf instead of tlog.Logf
     9  import (
    10  	"math"
    11  	"os"
    12  	"runtime"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/NVIDIA/aistore/cmn/cos"
    17  	"github.com/NVIDIA/aistore/sys"
    18  	"github.com/NVIDIA/aistore/tools/tassert"
    19  )
    20  
    21  func checkSkipOS(t *testing.T, os ...string) {
    22  	if cos.StringInSlice(runtime.GOOS, os) {
    23  		t.Skipf("skipping test for %s platform", runtime.GOOS)
    24  	}
    25  }
    26  
    27  func TestNumCPU(t *testing.T) {
    28  	checkSkipOS(t, "darwin")
    29  	if sys.NumCPU() < 1 || sys.NumCPU() > runtime.NumCPU() {
    30  		t.Errorf("Wrong number of CPUs %d (%d)", sys.NumCPU(), runtime.NumCPU())
    31  	}
    32  }
    33  
    34  func TestLoadAvg(t *testing.T) {
    35  	la, err := sys.LoadAverage()
    36  	tassert.CheckFatal(t, err)
    37  	t.Logf("Load average: %.2f, %.2f, %.2f\n", la.One, la.Five, la.Fifteen)
    38  	tassert.Errorf(t, la.One > 0.0 && la.Five > 0.0 && la.Fifteen > 0.0,
    39  		"All load average must be positive ones")
    40  }
    41  
    42  func TestLimitMaxProc(t *testing.T) {
    43  	prev := runtime.GOMAXPROCS(0)
    44  	defer runtime.GOMAXPROCS(prev)
    45  
    46  	ncpu := sys.NumCPU()
    47  	sys.SetMaxProcs()
    48  	curr := runtime.GOMAXPROCS(0)
    49  	tassert.Errorf(t, ncpu == curr, "Failed to set GOMAXPROCS to %d, current value is %d", ncpu, curr)
    50  }
    51  
    52  func TestMemoryStats(t *testing.T) {
    53  	var mem sys.MemStat
    54  	err := mem.Get()
    55  	tassert.CheckFatal(t, err)
    56  
    57  	tassert.Errorf(t, mem.Total > 0 && mem.Free > 0 && mem.ActualFree > 0 && mem.ActualUsed > 0,
    58  		"All items must be greater than zero: %+v", mem)
    59  	tassert.Errorf(t, mem.Total > mem.Free, "Free is greater than Total memory: %+v", mem)
    60  	tassert.Errorf(t, mem.Total > mem.Used, "Used is greater than Total memory: %+v", mem)
    61  	tassert.Errorf(t, mem.Total > mem.ActualUsed, "ActualUsed is greater than Total memory: %+v", mem)
    62  	tassert.Errorf(t, mem.Total > mem.ActualFree, "ActualFree is greater than Total memory: %+v", mem)
    63  	tassert.Errorf(t, mem.Total == mem.Free+mem.Used, "Total must be = Free + Used: %+v", mem)
    64  	t.Logf("Memory stats: %+v", mem)
    65  
    66  	checkSkipOS(t, "darwin")
    67  
    68  	var memHost, memCont sys.MemStat
    69  	err = memHost.Get()
    70  	tassert.CheckFatal(t, err)
    71  	tassert.Errorf(t, memHost.Total >= memCont.Total,
    72  		"Container's memory total is greater than the host one.\nOS: %+v\nContainer: %+v", memHost, memCont)
    73  	if memHost.SwapTotal == 0 && memHost.SwapFree == 0 {
    74  		// Not an error(e.g, Jenkins VM has swap off) - just a warning
    75  		t.Logf("Either swap is off or failed to read its stats")
    76  	}
    77  }
    78  
    79  func TestProc(t *testing.T) {
    80  	if testing.Short() {
    81  		t.Skipf("skipping %s in short mode", t.Name())
    82  	}
    83  	checkSkipOS(t, "darwin")
    84  
    85  	pid := os.Getpid()
    86  	stats, err := sys.ProcessStats(pid)
    87  	tassert.CheckFatal(t, err)
    88  	tassert.Errorf(t, stats.Mem.Size > 0 && stats.Mem.Resident > 0 && stats.Mem.Share > 0,
    89  		"Failed to read memory stats: %+v", stats.Mem)
    90  
    91  	// burn CPU for a few seconds by calculating prime numbers
    92  	// and make a short break to make usage lower than 100%
    93  	for i := range 20 {
    94  		n := int64(1)<<52 + int64((i*2)|1)
    95  		middle := int64(math.Sqrt(float64(n)))
    96  		divider := int64(3)
    97  		prime := true
    98  		for divider <= middle {
    99  			if n%divider == 0 {
   100  				prime = false
   101  			}
   102  			divider += 2
   103  		}
   104  		t.Logf("%d is prime: %v", n, prime)
   105  		time.Sleep(100 * time.Millisecond)
   106  	}
   107  
   108  	newStats, err := sys.ProcessStats(pid)
   109  	tassert.CheckFatal(t, err)
   110  	tassert.Errorf(t, newStats.CPU.User > 0, "Failed to read CPU stats: %+v", newStats.CPU)
   111  	tassert.Errorf(t, newStats.CPU.User+newStats.CPU.System == newStats.CPU.Total,
   112  		"Total must be equal to sum of User and System: %+v", newStats.CPU)
   113  	tassert.Errorf(t, newStats.CPU.Total > stats.CPU.Total, "New stats must show more CPU used. Old usage %d, new one: %d", stats.CPU.Total, newStats.CPU.Total)
   114  	tassert.Errorf(t, newStats.CPU.Percent > 0.0, "Process must use some CPU. Usage: %g", stats.CPU.Percent)
   115  	t.Logf("Process CPU usage: %6.2f%%", newStats.CPU.Percent)
   116  }