profiler/hotmid/main.go (79 lines of code) (raw):
// Copyright 2019 Google LLC
//
// 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
//
// https://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.
// Sample hotmid is an application that simulates multiple calls to a library
// function made via different call paths. Each of these calls is not
// particularly expensive (and so does not stand out on the flame graph). But
// in the aggregate these calls add up to a significant time which can be
// identified via looking at the flat list of functions' self and total time.
package main
import (
"flag"
"log"
"time"
"cloud.google.com/go/profiler"
)
var (
// version is the service version to configure.
version = flag.String("version", "1.0.0", "service version")
// seconds is the benchmark duration in seconds or 0 to run forever.
seconds = flag.Int("seconds", 0, "benchmark duration in seconds")
)
const spinCount = 1e6 // Ballpark to spin for ~0.5ms.
// Simulates a logging function that is called all over the place by the
// middleware. It illustrates the case of a function that is called by multiple
// call paths so it isn't immediately obvious as a hotspot when looking at a
// flame graph. Also note that the function itself does not have significant
// self time since it just calls out to other functions. So, to identify the
// function at its true cost, aggregation by total time is needed.
func myLog() {
myLogMutexLock()
myLogWrite()
myLogBuffer()
}
func myLogMutexLock() {
for i := 0; i < spinCount; i++ {
}
}
func myLogBuffer() {
for i := 0; i < 2*spinCount; i++ {
}
}
func myLogWrite() {
for i := 0; i < 5*spinCount; i++ {
}
}
func processItem(depth int) {
if depth == 0 {
return
}
for i := 0; i < 10*spinCount; i++ {
}
myLog()
processItem(depth - 1)
}
func foo1() {
processItem(5)
}
func foo2() {
processItem(5)
}
func foo3() {
processItem(10)
}
func foo4() {
processItem(10)
}
func foo5() {
processItem(15)
}
func foo6() {
processItem(15)
}
func run() {
start, duration := time.Now(), time.Duration(*seconds)*time.Second
for duration == 0 || time.Since(start) < duration {
foo1()
foo2()
foo3()
foo4()
foo5()
foo6()
}
}
func main() {
flag.Parse()
err := profiler.Start(profiler.Config{
Service: "hotmid-service",
ServiceVersion: *version,
DebugLogging: true,
})
if err != nil {
log.Fatalf("failed to start the profiler: %v", err)
}
run()
}