Enable profiler and profile-guided builds
I used the chance to simplify the Makefile, as this is required for the file check to work correctly. Variables should not contain quotes, as these will be included in the value otherwise.
This commit is contained in:

committed by
Sebastian Serth

parent
00952ca212
commit
1a378ce640
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,9 @@
|
|||||||
# Project binary
|
# Project binary
|
||||||
/poseidon
|
/poseidon
|
||||||
|
|
||||||
|
# CPU profiling information
|
||||||
|
cmd/poseidon/default.pgo
|
||||||
|
|
||||||
# Configuration file
|
# Configuration file
|
||||||
configuration.yaml
|
configuration.yaml
|
||||||
tests/e2e/configuration.yaml
|
tests/e2e/configuration.yaml
|
||||||
|
30
Makefile
30
Makefile
@ -1,19 +1,23 @@
|
|||||||
PROJECT_NAME := "poseidon"
|
PROJECT_NAME = poseidon
|
||||||
REPOSITORY_OWNER = "openHPI"
|
REPOSITORY_OWNER = openHPI
|
||||||
PKG := "github.com/$(REPOSITORY_OWNER)/$(PROJECT_NAME)/cmd/$(PROJECT_NAME)"
|
PKG = github.com/$(REPOSITORY_OWNER)/$(PROJECT_NAME)/cmd/$(PROJECT_NAME)
|
||||||
UNIT_TESTS = $(shell go list ./... | grep -v /e2e | grep -v /recovery)
|
UNIT_TESTS = $(shell go list ./... | grep -v /e2e | grep -v /recovery)
|
||||||
|
|
||||||
DOCKER_TAG := "poseidon:latest"
|
# Define the PGO file to be used for the build
|
||||||
DOCKER_OPTS := -v $(shell pwd)/configuration.yaml:/configuration.yaml
|
PGO_FILE = ./cmd/$(PROJECT_NAME)/default.pgo
|
||||||
|
|
||||||
|
# Docker options
|
||||||
|
DOCKER_TAG = poseidon:latest
|
||||||
|
DOCKER_OPTS = -v $(shell pwd)/configuration.yaml:/configuration.yaml
|
||||||
LOWER_REPOSITORY_OWNER = $(shell echo $(REPOSITORY_OWNER) | tr A-Z a-z)
|
LOWER_REPOSITORY_OWNER = $(shell echo $(REPOSITORY_OWNER) | tr A-Z a-z)
|
||||||
|
|
||||||
# Define image to be used in e2e tests. Requires `make` to be available.
|
# Define image to be used in e2e tests. Requires `make` to be available.
|
||||||
E2E_TEST_DOCKER_CONTAINER := co_execenv_java
|
E2E_TEST_DOCKER_CONTAINER = co_execenv_java
|
||||||
E2E_TEST_DOCKER_TAG := 17
|
E2E_TEST_DOCKER_TAG = 17
|
||||||
E2E_TEST_DOCKER_IMAGE = "$(LOWER_REPOSITORY_OWNER)/$(E2E_TEST_DOCKER_CONTAINER):$(E2E_TEST_DOCKER_TAG)"
|
E2E_TEST_DOCKER_IMAGE = $(LOWER_REPOSITORY_OWNER)/$(E2E_TEST_DOCKER_CONTAINER):$(E2E_TEST_DOCKER_TAG)
|
||||||
# The base image of the e2e test image. This is used to build the base image as well.
|
# The base image of the e2e test image. This is used to build the base image as well.
|
||||||
E2E_TEST_BASE_CONTAINER := docker_exec_phusion
|
E2E_TEST_BASE_CONTAINER := docker_exec_phusion
|
||||||
E2E_TEST_BASE_IMAGE = "$(LOWER_REPOSITORY_OWNER)/$(E2E_TEST_BASE_CONTAINER)"
|
E2E_TEST_BASE_IMAGE = $(LOWER_REPOSITORY_OWNER)/$(E2E_TEST_BASE_CONTAINER)
|
||||||
|
|
||||||
default: help
|
default: help
|
||||||
|
|
||||||
@ -45,7 +49,13 @@ git-hooks: .git/hooks/pre-commit ## Install the git-hooks
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: deps ## Build the binary
|
build: deps ## Build the binary
|
||||||
|
ifneq ("$(wildcard $(PGO_FILE))","")
|
||||||
|
# PGO_FILE exists
|
||||||
|
@go build -pgo=$(PGO_FILE) -ldflags "-X main.pgoEnabled=true" -o $(PROJECT_NAME) -v $(PKG)
|
||||||
|
else
|
||||||
|
# PGO_FILE does not exist
|
||||||
@go build -o $(PROJECT_NAME) -v $(PKG)
|
@go build -o $(PROJECT_NAME) -v $(PKG)
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: ## Remove previous build
|
clean: ## Remove previous build
|
||||||
@ -101,7 +111,7 @@ deploy/dockerfiles: ## Clone Dockerfiles repository
|
|||||||
|
|
||||||
.PHONY: e2e-test-docker-image
|
.PHONY: e2e-test-docker-image
|
||||||
e2e-test-docker-image: deploy/dockerfiles ## Build Docker image that is used in e2e tests
|
e2e-test-docker-image: deploy/dockerfiles ## Build Docker image that is used in e2e tests
|
||||||
@docker build -t $(E2E_TEST_BASE_IMAGE) -f deploy/dockerfiles/$(E2E_TEST_BASE_CONTAINER)
|
@docker build -t $(E2E_TEST_BASE_IMAGE) deploy/dockerfiles/$(E2E_TEST_BASE_CONTAINER)
|
||||||
@docker build -t $(E2E_TEST_DOCKER_IMAGE) deploy/dockerfiles/$(E2E_TEST_DOCKER_CONTAINER)/$(E2E_TEST_DOCKER_TAG)
|
@docker build -t $(E2E_TEST_DOCKER_IMAGE) deploy/dockerfiles/$(E2E_TEST_DOCKER_CONTAINER)/$(E2E_TEST_DOCKER_TAG)
|
||||||
|
|
||||||
.PHONY: e2e-test
|
.PHONY: e2e-test
|
||||||
|
@ -15,6 +15,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime/pprof"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -22,9 +24,21 @@ import (
|
|||||||
var (
|
var (
|
||||||
gracefulShutdownWait = 15 * time.Second
|
gracefulShutdownWait = 15 * time.Second
|
||||||
log = logging.GetLogger("main")
|
log = logging.GetLogger("main")
|
||||||
|
// If pgoEnabled is true, the binary was built with PGO enabled.
|
||||||
|
// This is set during compilation with our Makefile as a STRING.
|
||||||
|
pgoEnabled = "false"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initSentry(options *sentry.ClientOptions) {
|
func initSentry(options *sentry.ClientOptions, profilingEnabled bool) {
|
||||||
|
options.BeforeSendTransaction = func(event *sentry.Event, _ *sentry.EventHint) *sentry.Event {
|
||||||
|
if event.Tags == nil {
|
||||||
|
event.Tags = make(map[string]string)
|
||||||
|
}
|
||||||
|
event.Tags["go_pgo"] = pgoEnabled
|
||||||
|
event.Tags["go_profiling"] = strconv.FormatBool(profilingEnabled)
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
if err := sentry.Init(*options); err != nil {
|
if err := sentry.Init(*options); err != nil {
|
||||||
log.Errorf("sentry.Init: %s", err)
|
log.Errorf("sentry.Init: %s", err)
|
||||||
}
|
}
|
||||||
@ -37,6 +51,33 @@ func shutdownSentry() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initProfiling(options config.Profiling) (cancel func()) {
|
||||||
|
if options.Enabled {
|
||||||
|
profile, err := os.Create(options.File)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Error while opening the profile file")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Starting CPU profiler")
|
||||||
|
if err := pprof.StartCPUProfile(profile); err != nil {
|
||||||
|
log.WithError(err).Error("Error while starting the CPU profiler!!")
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel = func() {
|
||||||
|
if options.Enabled {
|
||||||
|
log.Debug("Stopping CPU profiler")
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
if err := profile.Close(); err != nil {
|
||||||
|
log.WithError(err).Error("Error while closing profile file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cancel = func() {}
|
||||||
|
}
|
||||||
|
return cancel
|
||||||
|
}
|
||||||
|
|
||||||
func runServer(server *http.Server) {
|
func runServer(server *http.Server) {
|
||||||
log.WithField("address", server.Addr).Info("Starting server")
|
log.WithField("address", server.Addr).Info("Starting server")
|
||||||
var err error
|
var err error
|
||||||
@ -139,9 +180,12 @@ func main() {
|
|||||||
log.WithError(err).Warn("Could not initialize configuration")
|
log.WithError(err).Warn("Could not initialize configuration")
|
||||||
}
|
}
|
||||||
logging.InitializeLogging(config.Config.Logger.Level)
|
logging.InitializeLogging(config.Config.Logger.Level)
|
||||||
initSentry(&config.Config.Sentry)
|
initSentry(&config.Config.Sentry, config.Config.Profiling.Enabled)
|
||||||
defer shutdownSentry()
|
defer shutdownSentry()
|
||||||
|
|
||||||
|
stopProfiling := initProfiling(config.Config.Profiling)
|
||||||
|
defer stopProfiling()
|
||||||
|
|
||||||
cancel := monitoring.InitializeInfluxDB(&config.Config.InfluxDB)
|
cancel := monitoring.InitializeInfluxDB(&config.Config.InfluxDB)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -61,6 +61,14 @@ logger:
|
|||||||
# Log level that is used after reading the config (INFO until then)
|
# Log level that is used after reading the config (INFO until then)
|
||||||
level: DEBUG
|
level: DEBUG
|
||||||
|
|
||||||
|
# Configuration of the embedded profiler
|
||||||
|
profiling:
|
||||||
|
# Enables the runtime profiler
|
||||||
|
enabled: false
|
||||||
|
# The file to which the profile is written to.
|
||||||
|
# The default location `cmd/poseidon/default.pgo` will be picked up during the build process to create a profile-guided build.
|
||||||
|
file: cmd/poseidon/default.pgo
|
||||||
|
|
||||||
# Configuration of the sentry logging
|
# Configuration of the sentry logging
|
||||||
sentry:
|
sentry:
|
||||||
# The DSN of the sentry endpoint to use.
|
# The DSN of the sentry endpoint to use.
|
||||||
|
@ -123,6 +123,12 @@ type logger struct {
|
|||||||
Level string
|
Level string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Profiling configures the usage of a runtime profiler to create optimized binaries.
|
||||||
|
type Profiling struct {
|
||||||
|
Enabled bool
|
||||||
|
File string
|
||||||
|
}
|
||||||
|
|
||||||
// InfluxDB configures the usage of an Influx db monitoring.
|
// InfluxDB configures the usage of an Influx db monitoring.
|
||||||
type InfluxDB struct {
|
type InfluxDB struct {
|
||||||
URL string
|
URL string
|
||||||
@ -134,12 +140,13 @@ type InfluxDB struct {
|
|||||||
|
|
||||||
// configuration contains the complete configuration of Poseidon.
|
// configuration contains the complete configuration of Poseidon.
|
||||||
type configuration struct {
|
type configuration struct {
|
||||||
Server server
|
Server server
|
||||||
Nomad Nomad
|
Nomad Nomad
|
||||||
AWS AWS
|
AWS AWS
|
||||||
Logger logger
|
Logger logger
|
||||||
Sentry sentry.ClientOptions
|
Profiling Profiling
|
||||||
InfluxDB InfluxDB
|
Sentry sentry.ClientOptions
|
||||||
|
InfluxDB InfluxDB
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitConfig merges configuration options from environment variables and
|
// InitConfig merges configuration options from environment variables and
|
||||||
|
Reference in New Issue
Block a user