github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_rusage.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package linux
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    22  	ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/usage"
    24  )
    25  
    26  func getrusage(t *kernel.Task, which int32) linux.Rusage {
    27  	var cs usage.CPUStats
    28  
    29  	switch which {
    30  	case linux.RUSAGE_SELF:
    31  		cs = t.ThreadGroup().CPUStats()
    32  
    33  	case linux.RUSAGE_CHILDREN:
    34  		cs = t.ThreadGroup().JoinedChildCPUStats()
    35  
    36  	case linux.RUSAGE_THREAD:
    37  		cs = t.CPUStats()
    38  
    39  	case linux.RUSAGE_BOTH:
    40  		tg := t.ThreadGroup()
    41  		cs = tg.CPUStats()
    42  		cs.Accumulate(tg.JoinedChildCPUStats())
    43  	}
    44  
    45  	return linux.Rusage{
    46  		UTime:  linux.NsecToTimeval(cs.UserTime.Nanoseconds()),
    47  		STime:  linux.NsecToTimeval(cs.SysTime.Nanoseconds()),
    48  		NVCSw:  int64(cs.VoluntarySwitches),
    49  		MaxRSS: int64(t.MaxRSS(which) / 1024),
    50  	}
    51  }
    52  
    53  // Getrusage implements linux syscall getrusage(2).
    54  //	marked "y" are supported now
    55  //	marked "*" are not used on Linux
    56  //	marked "p" are pending for support
    57  //
    58  //	y    struct timeval ru_utime; /* user CPU time used */
    59  //	y    struct timeval ru_stime; /* system CPU time used */
    60  //	p    long   ru_maxrss;        /* maximum resident set size */
    61  //	*    long   ru_ixrss;         /* integral shared memory size */
    62  //	*    long   ru_idrss;         /* integral unshared data size */
    63  //	*    long   ru_isrss;         /* integral unshared stack size */
    64  //	p    long   ru_minflt;        /* page reclaims (soft page faults) */
    65  //	p    long   ru_majflt;        /* page faults (hard page faults) */
    66  //	*    long   ru_nswap;         /* swaps */
    67  //	p    long   ru_inblock;       /* block input operations */
    68  //	p    long   ru_oublock;       /* block output operations */
    69  //	*    long   ru_msgsnd;        /* IPC messages sent */
    70  //	*    long   ru_msgrcv;        /* IPC messages received */
    71  //	*    long   ru_nsignals;      /* signals received */
    72  //	y    long   ru_nvcsw;         /* voluntary context switches */
    73  //	y    long   ru_nivcsw;        /* involuntary context switches */
    74  func Getrusage(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    75  	which := args[0].Int()
    76  	addr := args[1].Pointer()
    77  
    78  	if which != linux.RUSAGE_SELF && which != linux.RUSAGE_CHILDREN && which != linux.RUSAGE_THREAD {
    79  		return 0, nil, linuxerr.EINVAL
    80  	}
    81  
    82  	ru := getrusage(t, which)
    83  	_, err := ru.CopyOut(t, addr)
    84  	return 0, nil, err
    85  }
    86  
    87  // Times implements linux syscall times(2).
    88  func Times(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    89  	addr := args[0].Pointer()
    90  
    91  	// Calculate the ticks first, and figure out if any additional work is
    92  	// necessary. Linux allows for a NULL addr, in which case only the
    93  	// return value is meaningful. We don't need to do anything else.
    94  	ticks := uintptr(ktime.NowFromContext(t).Nanoseconds() / linux.ClockTick.Nanoseconds())
    95  	if addr == 0 {
    96  		return ticks, nil, nil
    97  	}
    98  
    99  	cs1 := t.ThreadGroup().CPUStats()
   100  	cs2 := t.ThreadGroup().JoinedChildCPUStats()
   101  	r := linux.Tms{
   102  		UTime:  linux.ClockTFromDuration(cs1.UserTime),
   103  		STime:  linux.ClockTFromDuration(cs1.SysTime),
   104  		CUTime: linux.ClockTFromDuration(cs2.UserTime),
   105  		CSTime: linux.ClockTFromDuration(cs2.SysTime),
   106  	}
   107  	if _, err := r.CopyOut(t, addr); err != nil {
   108  		return 0, nil, err
   109  	}
   110  
   111  	return ticks, nil, nil
   112  }