-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Runner is a thin library that's able to measure precise on-CPU time for the set of all goroutines run through it. It makes use of a (slightly) modified Go runtime in order to do so.
- Loading branch information
0 parents
commit f47cb8d
Showing
16 changed files
with
513 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build --symlink_prefix=.bazel/ | ||
run --ui_event_filters=-info,-stdout,-stderr --noshow_progress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.bazel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "modules/go"] | ||
path = modules/go | ||
url = [email protected]:irfansharif/go.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
load("@bazel_gazelle//:def.bzl", "gazelle") | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||
|
||
gazelle( | ||
name = "gazelle", | ||
prefix = "github.com/irfansharif/runner", | ||
) | ||
|
||
go_library( | ||
name = "runner", | ||
srcs = [ | ||
"runner.go", | ||
"runner.s", | ||
"runtime.go", | ||
], | ||
importpath = "github.com/irfansharif/runner", | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
go_test( | ||
name = "runner_test", | ||
srcs = [ | ||
"runner_test.go", | ||
"runtime_test.go", | ||
], | ||
embed = [":runner"], | ||
deps = ["@com_github_stretchr_testify//assert"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
load("@bazel_gazelle//:deps.bzl", "go_repository") | ||
|
||
def go_deps(): | ||
go_repository( | ||
name = "com_github_davecgh_go_spew", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "github.com/davecgh/go-spew", | ||
sum = "h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=", | ||
version = "v1.1.0", | ||
) | ||
go_repository( | ||
name = "com_github_pmezard_go_difflib", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "github.com/pmezard/go-difflib", | ||
sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=", | ||
version = "v1.0.0", | ||
) | ||
|
||
go_repository( | ||
name = "com_github_stretchr_objx", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "github.com/stretchr/objx", | ||
sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=", | ||
version = "v0.1.0", | ||
) | ||
|
||
go_repository( | ||
name = "com_github_stretchr_testify", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "github.com/stretchr/testify", | ||
sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", | ||
version = "v1.7.0", | ||
) | ||
go_repository( | ||
name = "in_gopkg_check_v1", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "gopkg.in/check.v1", | ||
sum = "h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=", | ||
version = "v0.0.0-20161208181325-20d25e280405", | ||
) | ||
go_repository( | ||
name = "in_gopkg_yaml_v3", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "gopkg.in/yaml.v3", | ||
sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=", | ||
version = "v3.0.0-20200313102051-9f266ea9e77c", | ||
) | ||
go_repository( | ||
name = "org_golang_x_sync", | ||
build_file_proto_mode = "disable_global", | ||
importpath = "golang.org/x/sync", | ||
sum = "h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=", | ||
version = "v0.0.0-20210220032951-036812b2e83c", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright 2022 Irfan Sharif. | ||
# | ||
# 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. | ||
|
||
test: | ||
bazel test //:all --test_arg='-test.v' --test_output=all | ||
|
||
bench: | ||
bazel test //:all --nocache_test_results \ | ||
--test_arg='-test.v' --test_output=all --test_arg='-test.run=-' \ | ||
--test_arg='-test.bench=.' --test_arg='-test.benchtime=10000x' | ||
|
||
generate: FORCE | ||
bazel run //:gazelle -- update-repos \ | ||
-from_file=go.mod -prune=true \ | ||
-build_file_proto_mode=disable_global \ | ||
-to_macro=DEPS.bzl%go_deps &> /dev/null | ||
bazel run //:gazelle &> /dev/null | ||
|
||
go: | ||
git submodule update --init --recursive | ||
cd modules/go/src && ./make.bash | ||
|
||
FORCE: ; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
Runner | ||
--- | ||
|
||
[![Go Reference](https://pkg.go.dev/badge/github.com/irfansharif/runner.svg)](https://godocs.io/github.com/irfansharif/runner) | ||
|
||
Runner is a thin library that's able to precisely measure on-CPU time for | ||
goroutines. It relies on a slightly modified Go runtime for additional | ||
instrumentation in order to function. It's a prototype for what finer-grained | ||
CPU attribution could look like in Go. | ||
|
||
### Contributing | ||
|
||
The repo includes the necessary Go runtime as a submodule. To get up and | ||
running (assumes you already have `go` installed and in your `PATH`): | ||
|
||
```sh | ||
$ git clone [email protected]:irfansharif/runner.git | ||
$ cd runner | ||
$ make go # set up submodules and build the modified go runtime | ||
``` | ||
|
||
We can now use the modified Go to run tests: | ||
```sh | ||
$ modules/go/bin/go test -v . | ||
``` | ||
|
||
To develop using bazel, we need to tell it to build using the modified runtime. | ||
To do so, edit the following portion of the top-level `WORKSPACE` to point to | ||
the cloned `go` submodule with the runtime changes: | ||
|
||
```python | ||
go_local_sdk( | ||
name = "go_sdk", | ||
path = "<path to checkout>/modules/go", | ||
) | ||
``` | ||
|
||
Finally, run the package tests/benchmarks or update BUILD files: | ||
|
||
``` | ||
$ make test | ||
$ make bench | ||
$ make generate | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
workspace(name = "hello") | ||
|
||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | ||
|
||
http_archive( | ||
name = "io_bazel_rules_go", | ||
sha256 = "5c4bd27429b1a307d51cd23d4677126aa6315fff608f0cd85c5bfb642a13b953", | ||
strip_prefix = "cockroachdb-rules_go-23b381c", | ||
urls = [ | ||
"https://storage.googleapis.com/public-bazel-artifacts/bazel/cockroachdb-rules_go-v0.27.0-52-g23b381c.tar.gz", | ||
], | ||
) | ||
|
||
# Load gazelle. This lets us auto-generate BUILD.bazel files throughout the | ||
# repo. | ||
http_archive( | ||
name = "bazel_gazelle", | ||
sha256 = "9fba095e4bebd8c6748154ca53c365862af47fa1651f7c0d25459e6ca5bb208f", | ||
strip_prefix = "bazelbuild-bazel-gazelle-3ea1d64", | ||
urls = [ | ||
# v0.24.0 | ||
"https://storage.googleapis.com/public-bazel-artifacts/bazel/bazelbuild-bazel-gazelle-v0.24.0-0-g3ea1d64.tar.gz", | ||
], | ||
) | ||
|
||
# Load up go dependencies (the ones listed under go.mod). | ||
load("//:DEPS.bzl", "go_deps") | ||
|
||
# gazelle:repository_macro DEPS.bzl%go_deps | ||
go_deps() | ||
|
||
load( | ||
"@io_bazel_rules_go//go:deps.bzl", | ||
"go_local_sdk", | ||
"go_rules_dependencies", | ||
) | ||
|
||
# TODO(irfansharif): Point to mirrored, public URL with modified runtime. For | ||
# now this points to local checkout of go source tree. | ||
go_local_sdk( | ||
name = "go_sdk", | ||
path = "/Users/irfansharif/Software/src/github.com/irfansharif/runner/modules/go", | ||
) | ||
|
||
go_rules_dependencies() | ||
|
||
# Load gazelle dependencies. | ||
load( | ||
"@bazel_gazelle//:deps.bzl", | ||
"gazelle_dependencies", | ||
"go_repository", | ||
) | ||
|
||
gazelle_dependencies() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module github.com/irfansharif/runner | ||
|
||
go 1.17 | ||
|
||
require github.com/stretchr/testify v1.7.0 | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.0 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | ||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright 2022 Irfan Sharif. | ||
// | ||
// 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 runner is a library that's able to precisely measure on-CPU time for | ||
// goroutines. | ||
package runner | ||
|
||
import ( | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
// TODO(irfansharif): | ||
// | ||
// - Make use of buildtags. Use smoketests to check if things are up to snuff? | ||
// Currently we fails with an opaque link error if not using the right go SDK. | ||
// - Write out steps to download patched runtime. | ||
// - Provide a default singleton runner for instances where plumbing in a runner | ||
// is inconvenient. | ||
// - Maintain tags/task names and some bounded sketch of runner history. | ||
|
||
// TODO(irfansharif): We only accumulate on-CPU time at the end of the invoked | ||
// goroutine; there's no "inflight" view of ops. This post-hoc capture might be | ||
// unsuitable for long-running goroutines unless we provide an API to | ||
// periodically record on-CPU time, and/or perform taskgroup[1]-style tracking | ||
// within the runtime. | ||
// | ||
// [1]: https://github.com/cockroachdb/cockroach/pull/60589 | ||
|
||
// Runner is able to measure precise on-CPU time for the set of all goroutines | ||
// run through it. | ||
type Runner struct { | ||
nanos int64 // accessed atomically | ||
} | ||
|
||
// New returns a new Runner. | ||
func New() *Runner { | ||
return &Runner{} | ||
} | ||
|
||
// Run the given function in a new goroutine. | ||
func (r *Runner) Run(f func()) { | ||
go func() { | ||
f() | ||
atomic.AddInt64(&r.nanos, grunningnanos()) // record the running nanoseconds for the goroutine | ||
}() | ||
} | ||
|
||
// Duration returns the total running (i.e. on CPU) duration observed by all | ||
// goroutines run under the group. | ||
func (r *Runner) Duration() time.Duration { | ||
return time.Duration(atomic.LoadInt64(&r.nanos)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// We need a .s file so the Go tool does not pass -complete to go tool compile; | ||
// that'd prevent being able to define functions with no bodies (something this | ||
// package uses to link into private runtime methods). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2022 Irfan Sharif. | ||
// | ||
// 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 runner_test | ||
|
||
import ( | ||
"fmt" | ||
"runtime" | ||
"sync" | ||
"testing" | ||
"time" | ||
|
||
"github.com/irfansharif/runner" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestRunDuration tests that run durations behaves as expected. | ||
func TestRunDuration(t *testing.T) { | ||
for _, work := range []string{"busy", "lazy"} { | ||
work := work | ||
t.Run(fmt.Sprintf("loop=%s", work), func(t *testing.T) { | ||
var wg sync.WaitGroup | ||
r := runner.New() | ||
|
||
start := time.Now() | ||
for i := 0; i < 10; i++ { | ||
wg.Add(1) | ||
r.Run(func() { | ||
defer wg.Done() | ||
|
||
if work == "busy" { | ||
runner.TestingBusyFn() | ||
} else { | ||
runner.TestingLazyFn() | ||
} | ||
}) | ||
} | ||
wg.Wait() | ||
|
||
walltime := time.Since(start) | ||
cputime := r.Duration() | ||
mult := float64(cputime.Nanoseconds()) / float64(walltime.Nanoseconds()) | ||
|
||
if work == "busy" { | ||
minexp := float64(runtime.GOMAXPROCS(-1)) - 1 | ||
assert.Greaterf(t, mult, minexp, | ||
"expected multiplier > %f, got %f", minexp, mult) | ||
} else { | ||
maxexp := float64(0.1) | ||
assert.Lessf(t, mult, maxexp, | ||
"expected approximately zero multiplier, got %f", mult) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.