in ethr.go [27:246]
func main() {
//
// If version is not set via ldflags, then default to UNKNOWN
//
if gVersion == "" {
gVersion = "UNKNOWN"
}
fmt.Println("\nEthr: Comprehensive Network Performance Measurement Tool (Version: " + gVersion + ")")
fmt.Println("Maintainer: Pankaj Garg (ipankajg @ LinkedIn | GitHub | Gmail | Twitter)")
fmt.Println("")
//
// Set GOMAXPROCS to 1024 as running large number of goroutines that send
// data in a tight loop over network is resulting in unfair time allocation
// across goroutines causing starvation of many TCP connections. Using a
// higher number of threads via GOMAXPROCS solves this problem.
//
runtime.GOMAXPROCS(1024)
// Common
flag.Usage = func() { ethrUsage() }
noOutput := flag.Bool("no", false, "")
outputFile := flag.String("o", defaultLogFileName, "")
debug := flag.Bool("debug", false, "")
use4 := flag.Bool("4", false, "")
use6 := flag.Bool("6", false, "")
port := flag.Int("port", 8888, "")
ip := flag.String("ip", "", "")
// Server
isServer := flag.Bool("s", false, "")
showUI := flag.Bool("ui", false, "")
// Client & External Client
clientDest := flag.String("c", "", "")
bufLenStr := flag.String("l", "", "")
bwRateStr := flag.String("b", "", "")
cport := flag.Int("cport", 0, "")
duration := flag.Duration("d", 10*time.Second, "")
gap := flag.Duration("g", time.Second, "")
iterCount := flag.Int("i", 1000, "")
ncs := flag.Bool("ncs", false, "")
protocol := flag.String("p", "tcp", "")
reverse := flag.Bool("r", false, "")
testTypePtr := flag.String("t", "", "")
tos := flag.Int("tos", 0, "")
title := flag.String("T", "", "")
thCount := flag.Int("n", 1, "")
wc := flag.Int("w", 1, "")
xClientDest := flag.String("x", "", "")
flag.Parse()
if *isServer {
if *clientDest != "" {
printUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".")
}
if *xClientDest != "" {
printUsageError("Invalid arguments, \"-x\" cannot be used with \"-s\".")
}
if *bufLenStr != "" {
printServerModeArgError("l")
}
if *bwRateStr != "" {
printServerModeArgError("b")
}
if *cport != 0 {
printServerModeArgError("cport")
}
if *duration != 10*time.Second {
printServerModeArgError("d")
}
if *gap != time.Second {
printServerModeArgError("g")
}
if *iterCount != 1000 {
printServerModeArgError("i")
}
if *ncs {
printServerModeArgError("ncs")
}
if *protocol != "tcp" {
printServerModeArgError("p")
}
if *reverse {
printServerModeArgError("r")
}
if *testTypePtr != "" {
printServerModeArgError("t")
}
if *tos != 0 {
printServerModeArgError("tos")
}
if *thCount != 1 {
printServerModeArgError("n")
}
if *wc != 1 {
printServerModeArgError("wc")
}
if *title != "" {
printServerModeArgError("T")
}
} else if *clientDest != "" || *xClientDest != "" {
if *clientDest != "" && *xClientDest != "" {
printUsageError("Invalid argument, both \"-c\" and \"-x\" cannot be specified at the same time.")
}
if *showUI {
printUsageError(fmt.Sprintf("Invalid argument, \"-%s\" can only be used in server (\"-s\") mode.", "ui"))
}
} else {
printUsageError("Invalid arguments, use either \"-s\" or \"-c\".")
}
// Process common parameters.
if *debug {
loggingLevel = LogLevelDebug
}
if *use4 && !*use6 {
gIPVersion = ethrIPv4
} else if *use6 && !*use4 {
gIPVersion = ethrIPv6
}
if *ip != "" {
gLocalIP = *ip
ipAddr := net.ParseIP(gLocalIP)
if ipAddr == nil {
printUsageError(fmt.Sprintf("Invalid IP address: <%s> specified.", *ip))
}
if (gIPVersion == ethrIPv4 && ipAddr.To4() == nil) || (gIPVersion == ethrIPv6 && ipAddr.To16() == nil) {
printUsageError(fmt.Sprintf("Invalid IP address version: <%s> specified.", *ip))
}
}
gEthrPort = uint16(*port)
gEthrPortStr = fmt.Sprintf("%d", gEthrPort)
logFileName := *outputFile
if !*noOutput {
if logFileName == defaultLogFileName {
if *isServer {
logFileName = "ethrs.log"
} else {
logFileName = "ethrc.log"
}
}
logInit(logFileName)
}
var testType EthrTestType
var destination string
if *isServer {
// Server side parameter processing.
testType = All
serverParam := ethrServerParam{*showUI}
runServer(serverParam)
} else {
gIsExternalClient = false
destination = *clientDest
if *xClientDest != "" {
gIsExternalClient = true
destination = *xClientDest
}
gNoConnectionStats = *ncs
testType = getTestType(*testTypePtr)
proto := getProtocol(*protocol)
// Default latency test to 1B if length is not specified
switch *bufLenStr {
case "":
*bufLenStr = getDefaultBufferLenStr(*testTypePtr)
}
bufLen := unitToNumber(*bufLenStr)
if bufLen == 0 {
printUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr))
}
// Check specific bwRate if any.
bwRate := uint64(0)
if *bwRateStr != "" {
bwRate = unitToNumber(*bwRateStr)
bwRate /= 8
}
//
// For Pkt/s, we always override the buffer size to be just 1 byte.
// TODO: Evaluate in future, if we need to support > 1 byte packets for
// Pkt/s testing.
//
if testType == Pps {
bufLen = 1
}
if *iterCount <= 0 {
printUsageError(fmt.Sprintf("Invalid iteration count for latency test: %d", *iterCount))
}
if *thCount <= 0 {
*thCount = runtime.NumCPU()
}
gClientPort = uint16(*cport)
testId := EthrTestID{EthrProtocol(proto), testType}
clientParam := EthrClientParam{
uint32(*thCount),
uint32(bufLen),
uint32(*iterCount),
*reverse,
*duration,
*gap,
uint32(*wc),
uint64(bwRate),
uint8(*tos)}
validateClientParams(testId, clientParam)
rServer := destination
runClient(testId, *title, clientParam, rServer)
}
}