syscall_linux.go (3214B)
1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package syscall provides functionalities that grpc uses to get low-level operating system 20 // stats/info. 21 package syscall 22 23 import ( 24 "fmt" 25 "net" 26 "syscall" 27 "time" 28 29 "golang.org/x/sys/unix" 30 "google.golang.org/grpc/grpclog" 31 ) 32 33 var logger = grpclog.Component("core") 34 35 // GetCPUTime returns the how much CPU time has passed since the start of this process. 36 func GetCPUTime() int64 { 37 var ts unix.Timespec 38 if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { 39 logger.Fatal(err) 40 } 41 return ts.Nano() 42 } 43 44 // Rusage is an alias for syscall.Rusage under linux environment. 45 type Rusage = syscall.Rusage 46 47 // GetRusage returns the resource usage of current process. 48 func GetRusage() *Rusage { 49 rusage := new(Rusage) 50 syscall.Getrusage(syscall.RUSAGE_SELF, rusage) 51 return rusage 52 } 53 54 // CPUTimeDiff returns the differences of user CPU time and system CPU time used 55 // between two Rusage structs. 56 func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { 57 var ( 58 utimeDiffs = latest.Utime.Sec - first.Utime.Sec 59 utimeDiffus = latest.Utime.Usec - first.Utime.Usec 60 stimeDiffs = latest.Stime.Sec - first.Stime.Sec 61 stimeDiffus = latest.Stime.Usec - first.Stime.Usec 62 ) 63 64 uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6 65 sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6 66 67 return uTimeElapsed, sTimeElapsed 68 } 69 70 // SetTCPUserTimeout sets the TCP user timeout on a connection's socket 71 func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { 72 tcpconn, ok := conn.(*net.TCPConn) 73 if !ok { 74 // not a TCP connection. exit early 75 return nil 76 } 77 rawConn, err := tcpconn.SyscallConn() 78 if err != nil { 79 return fmt.Errorf("error getting raw connection: %v", err) 80 } 81 err = rawConn.Control(func(fd uintptr) { 82 err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond)) 83 }) 84 if err != nil { 85 return fmt.Errorf("error setting option on socket: %v", err) 86 } 87 88 return nil 89 } 90 91 // GetTCPUserTimeout gets the TCP user timeout on a connection's socket 92 func GetTCPUserTimeout(conn net.Conn) (opt int, err error) { 93 tcpconn, ok := conn.(*net.TCPConn) 94 if !ok { 95 err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn) 96 return 97 } 98 rawConn, err := tcpconn.SyscallConn() 99 if err != nil { 100 err = fmt.Errorf("error getting raw connection: %v", err) 101 return 102 } 103 err = rawConn.Control(func(fd uintptr) { 104 opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT) 105 }) 106 if err != nil { 107 err = fmt.Errorf("error getting option on socket: %v", err) 108 return 109 } 110 111 return 112 }