From 625bab2130948a38d8cfe140297f8249ba0c6fcb Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 30 Nov 2022 12:38:18 +0100 Subject: [PATCH 1/3] Add Makefile and Dockerized build Signed-off-by: Evan Lezar --- Makefile | 115 ++++++++++++++++++++++++++++++++++++++++ docker/Dockerfile.devel | 17 ++++++ 2 files changed, 132 insertions(+) create mode 100644 Makefile create mode 100644 docker/Dockerfile.devel diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8df5c90 --- /dev/null +++ b/Makefile @@ -0,0 +1,115 @@ +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# 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. + +MODULE := github.com/nvidia/go-gpuallocator + +DOCKER ?= docker + +GOLANG_VERSION := 1.15 + +ifeq ($(IMAGE),) +REGISTRY ?= nvidia +IMAGE=$(REGISTRY)/go-gpuallocator +endif +IMAGE_TAG ?= $(GOLANG_VERSION) +BUILDIMAGE ?= $(IMAGE):$(IMAGE_TAG)-devel + +TARGETS := binary build all check fmt assert-fmt generate lint vet test coverage +DOCKER_TARGETS := $(patsubst %, docker-%, $(TARGETS)) +.PHONY: $(TARGETS) $(DOCKER_TARGETS) + +GOOS := linux + +build: + GOOS=$(GOOS) go build ./... + +all: check build binary +check: assert-fmt lint vet + +# Apply go fmt to the codebase +fmt: + go list -f '{{.Dir}}' $(MODULE)/... \ + | xargs gofmt -s -l -w + +assert-fmt: + go list -f '{{.Dir}}' $(MODULE)/... \ + | xargs gofmt -s -l > fmt.out + @if [ -s fmt.out ]; then \ + echo "\nERROR: The following files are not formatted:\n"; \ + cat fmt.out; \ + rm fmt.out; \ + exit 1; \ + else \ + rm fmt.out; \ + fi + +generate: + go generate $(MODULE)/... + +lint: + # We use `go list -f '{{.Dir}}' $(MODULE)/...` to skip the `vendor` folder. + go list -f '{{.Dir}}' $(MODULE)/... | grep -v pkg/nvml | xargs golint -set_exit_status + +vet: + go vet $(MODULE)/... + +COVERAGE_FILE := coverage.out +test: build + go test -v -coverprofile=$(COVERAGE_FILE) $(MODULE)/... + +coverage: test + cat $(COVERAGE_FILE) | grep -v "_mock.go" > $(COVERAGE_FILE).no-mocks + go tool cover -func=$(COVERAGE_FILE).no-mocks + +# Generate an image for containerized builds +# Note: This image is local only +.PHONY: .build-image .pull-build-image .push-build-image +.build-image: docker/Dockerfile.devel + if [ "$(SKIP_IMAGE_BUILD)" = "" ]; then \ + $(DOCKER) build \ + --progress=plain \ + --build-arg GOLANG_VERSION="$(GOLANG_VERSION)" \ + --tag $(BUILDIMAGE) \ + -f $(^) \ + docker; \ + fi + +.pull-build-image: + $(DOCKER) pull $(BUILDIMAGE) + +.push-build-image: + $(DOCKER) push $(BUILDIMAGE) + +$(DOCKER_TARGETS): docker-%: .build-image + @echo "Running 'make $(*)' in docker container $(BUILDIMAGE)" + $(DOCKER) run \ + --rm \ + -e GOCACHE=/tmp/.cache \ + -v $(PWD):$(PWD) \ + -w $(PWD) \ + --user $$(id -u):$$(id -g) \ + $(BUILDIMAGE) \ + make $(*) + +# Start an interactive shell using the development image. +PHONY: .shell +.shell: + $(DOCKER) run \ + --rm \ + -ti \ + -e GOCACHE=/tmp/.cache \ + -v $(PWD):$(PWD) \ + -w $(PWD) \ + --user $$(id -u):$$(id -g) \ + $(BUILDIMAGE) diff --git a/docker/Dockerfile.devel b/docker/Dockerfile.devel new file mode 100644 index 0000000..d3a8308 --- /dev/null +++ b/docker/Dockerfile.devel @@ -0,0 +1,17 @@ +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# 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. +ARG GOLANG_VERSION=1.15 +FROM golang:${GOLANG_VERSION} + +RUN go get -u golang.org/x/lint/golint From f1f3de8d3686a5919317593edc39e1f6c41748bb Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 30 Nov 2022 12:38:43 +0100 Subject: [PATCH 2/3] Run make fmt Signed-off-by: Evan Lezar --- gpuallocator/besteffort_policy.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/gpuallocator/besteffort_policy.go b/gpuallocator/besteffort_policy.go index af1b40c..acb697e 100644 --- a/gpuallocator/besteffort_policy.go +++ b/gpuallocator/besteffort_policy.go @@ -15,22 +15,22 @@ func NewBestEffortPolicy() Policy { return &bestEffortPolicy{} } -// Allocate finds the best set of 'size' GPUs to allocate from a list of -// available GPU devices and returns them. The algorithm is designed to -// ensure that a list of 'required' GPU devices is present in the final -// allocation. +// Allocate finds the best set of 'size' GPUs to allocate from a list of +// available GPU devices and returns them. The algorithm is designed to +// ensure that a list of 'required' GPU devices is present in the final +// allocation. // -// This algorithm considers all possible sets of GPUs of size 'size'. -// However, it does not settle for the greedy solution of looking for the -// single set of size 'size' with the highest score. Instead, it looks for a -// solution that maximizes the total score when dividing up all available -// GPUs on the node into sets of size 'size' and then summing their -// individual scores. It then returns the set of GPUs from that grouping -// with the highest individual score. +// This algorithm considers all possible sets of GPUs of size 'size'. +// However, it does not settle for the greedy solution of looking for the +// single set of size 'size' with the highest score. Instead, it looks for a +// solution that maximizes the total score when dividing up all available +// GPUs on the node into sets of size 'size' and then summing their +// individual scores. It then returns the set of GPUs from that grouping +// with the highest individual score. // -// Such a solution is necessary in the general case because of the -// non-hierarchical nature of the various links that influence the score -// calculated for each pair of GPUs. +// Such a solution is necessary in the general case because of the +// non-hierarchical nature of the various links that influence the score +// calculated for each pair of GPUs. func (p *bestEffortPolicy) Allocate(available []*Device, required []*Device, size int) []*Device { if size <= 0 { return []*Device{} @@ -218,7 +218,7 @@ func iterateGPUPartitions(devices []*Device, size int, callback func([][]*Device // Optimize for the case when size == 1. if size == 1 { for _, device := range devices { - callback([][]*Device{[]*Device{device}}) + callback([][]*Device{{device}}) } return } From 7260457258696d50239d55dd5d1dcd694af3a804 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 30 Nov 2022 12:39:50 +0100 Subject: [PATCH 3/3] Address make check errors Signed-off-by: Evan Lezar --- gpuallocator/device.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gpuallocator/device.go b/gpuallocator/device.go index be2ff5c..eecd7f2 100644 --- a/gpuallocator/device.go +++ b/gpuallocator/device.go @@ -29,7 +29,7 @@ type P2PLink struct { // DeviceSet is used to hold and manipulate a set of unique GPU devices. type DeviceSet map[string]*Device -// Create a list of Devices from all available nvml.Devices. +// NewDevices creates a list of Devices from all available nvml.Devices. func NewDevices() ([]*Device, error) { count, err := nvml.GetDeviceCount() if err != nil { @@ -71,7 +71,7 @@ func NewDevices() ([]*Device, error) { return devices, nil } -// Create a list of Devices from the specific set of GPU uuids passed in. +// NewDevicesFrom creates a list of Devices from the specific set of GPU uuids passed in. func NewDevicesFrom(uuids []string) ([]*Device, error) { devices, err := NewDevices() if err != nil {