You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.2 KiB
114 lines
3.2 KiB
// +build !appengine |
|
|
|
/* |
|
* |
|
* Copyright 2018 gRPC 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. |
|
* |
|
*/ |
|
|
|
// Package syscall provides functionalities that grpc uses to get low-level operating system |
|
// stats/info. |
|
package syscall |
|
|
|
import ( |
|
"fmt" |
|
"net" |
|
"syscall" |
|
"time" |
|
|
|
"golang.org/x/sys/unix" |
|
"google.golang.org/grpc/grpclog" |
|
) |
|
|
|
// GetCPUTime returns the how much CPU time has passed since the start of this process. |
|
func GetCPUTime() int64 { |
|
var ts unix.Timespec |
|
if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { |
|
grpclog.Fatal(err) |
|
} |
|
return ts.Nano() |
|
} |
|
|
|
// Rusage is an alias for syscall.Rusage under linux non-appengine environment. |
|
type Rusage syscall.Rusage |
|
|
|
// GetRusage returns the resource usage of current process. |
|
func GetRusage() (rusage *Rusage) { |
|
rusage = new(Rusage) |
|
syscall.Getrusage(syscall.RUSAGE_SELF, (*syscall.Rusage)(rusage)) |
|
return |
|
} |
|
|
|
// CPUTimeDiff returns the differences of user CPU time and system CPU time used |
|
// between two Rusage structs. |
|
func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { |
|
f := (*syscall.Rusage)(first) |
|
l := (*syscall.Rusage)(latest) |
|
var ( |
|
utimeDiffs = l.Utime.Sec - f.Utime.Sec |
|
utimeDiffus = l.Utime.Usec - f.Utime.Usec |
|
stimeDiffs = l.Stime.Sec - f.Stime.Sec |
|
stimeDiffus = l.Stime.Usec - f.Stime.Usec |
|
) |
|
|
|
uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6 |
|
sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6 |
|
|
|
return uTimeElapsed, sTimeElapsed |
|
} |
|
|
|
// SetTCPUserTimeout sets the TCP user timeout on a connection's socket |
|
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { |
|
tcpconn, ok := conn.(*net.TCPConn) |
|
if !ok { |
|
// not a TCP connection. exit early |
|
return nil |
|
} |
|
rawConn, err := tcpconn.SyscallConn() |
|
if err != nil { |
|
return fmt.Errorf("error getting raw connection: %v", err) |
|
} |
|
err = rawConn.Control(func(fd uintptr) { |
|
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond)) |
|
}) |
|
if err != nil { |
|
return fmt.Errorf("error setting option on socket: %v", err) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// GetTCPUserTimeout gets the TCP user timeout on a connection's socket |
|
func GetTCPUserTimeout(conn net.Conn) (opt int, err error) { |
|
tcpconn, ok := conn.(*net.TCPConn) |
|
if !ok { |
|
err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn) |
|
return |
|
} |
|
rawConn, err := tcpconn.SyscallConn() |
|
if err != nil { |
|
err = fmt.Errorf("error getting raw connection: %v", err) |
|
return |
|
} |
|
err = rawConn.Control(func(fd uintptr) { |
|
opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT) |
|
}) |
|
if err != nil { |
|
err = fmt.Errorf("error getting option on socket: %v", err) |
|
return |
|
} |
|
|
|
return |
|
}
|
|
|