Ctrl K
ComunidadGuías…

lab_profile.go

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
//go:build labprofile

// lab_profile.go is deliberately excluded from the normal build. It provides
// a finite, file-only profiler for controlled throughput experiments in owned
// lab environments. It does not register an HTTP handler or expose pprof.
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	labProfileEnabledEnv       = "P2PSTREAM_LABPROFILE"
	labProfileSecondsEnv       = "P2PSTREAM_LABPROFILE_SECONDS"
	labProfileDirEnv           = "P2PSTREAM_LABPROFILE_DIR"
	labProfileCPUPathEnv       = "P2PSTREAM_LABPROFILE_CPU"
	labProfileHeapPathEnv      = "P2PSTREAM_LABPROFILE_HEAP"
	labProfileBlockRateEnv     = "P2PSTREAM_LABPROFILE_BLOCK_RATE"
	labProfileMutexFractionEnv = "P2PSTREAM_LABPROFILE_MUTEX_FRACTION"
)

type labProfile struct {
	cpuPath       string
	heapPath      string
	goroutinePath string
	blockPath     string
	mutexPath     string

	cpuFile *os.File
	once    sync.Once
}

func init() {
	if !labProfileTruthy(os.Getenv(labProfileEnabledEnv)) {
		return
	}

	seconds, err := labProfileSeconds()
	if err != nil {
		fmt.Fprintf(os.Stderr, "labprofile disabled: %v\n", err)
		return
	}
	profile, err := newLabProfile()
	if err != nil {
		fmt.Fprintf(os.Stderr, "labprofile disabled: %v\n", err)
		return
	}
	if err := profile.start(); err != nil {
		fmt.Fprintf(os.Stderr, "labprofile disabled: %v\n", err)
		return
	}

	fmt.Fprintf(os.Stderr, "labprofile enabled for %s; cpu=%s heap=%s\n", seconds, profile.cpuPath, profile.heapPath)
	go func() {
		timer := time.NewTimer(seconds)
		defer timer.Stop()
		<-timer.C
		profile.finish()
	}()
}

func labProfileTruthy(value string) bool {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "1", "true", "yes", "y", "on":
		return true
	default:
		return false
	}
}

func labProfileSeconds() (time.Duration, error) {
	raw := strings.TrimSpace(os.Getenv(labProfileSecondsEnv))
	if raw == "" {
		raw = "60"
	}
	seconds, err := strconv.ParseInt(raw, 10, 64)
	if err != nil || seconds <= 0 || seconds > int64((time.Duration(1<<63-1))/time.Second) {
		return 0, fmt.Errorf("%s must be a positive integer number of seconds", labProfileSecondsEnv)
	}
	return time.Duration(seconds) * time.Second, nil
}

func newLabProfile() (*labProfile, error) {
	dir := strings.TrimSpace(os.Getenv(labProfileDirEnv))
	if dir == "" {
		dir = filepath.Join("tmp", "throughput-profiling")
	}
	if err := os.MkdirAll(dir, 0o700); err != nil {
		return nil, fmt.Errorf("create profile directory %q: %w", dir, err)
	}

	pathFor := func(env, name string) string {
		if value := strings.TrimSpace(os.Getenv(env)); value != "" {
			return value
		}
		return filepath.Join(dir, name)
	}
	return &labProfile{
		cpuPath:       pathFor(labProfileCPUPathEnv, "cpu.pprof"),
		heapPath:      pathFor(labProfileHeapPathEnv, "heap.pprof"),
		goroutinePath: filepath.Join(dir, "goroutine.pprof"),
	}, nil
}

func (p *labProfile) start() error {
	if err := ensureLabProfileParent(p.cpuPath); err != nil {
		return fmt.Errorf("create CPU profile parent: %w", err)
	}
	file, err := os.OpenFile(p.cpuPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
	if err != nil {
		return fmt.Errorf("open CPU profile %q: %w", p.cpuPath, err)
	}
	if err := pprof.StartCPUProfile(file); err != nil {
		_ = file.Close()
		return fmt.Errorf("start CPU profile: %w", err)
	}
	p.cpuFile = file

	blockRate, err := labProfileNonNegativeInt(labProfileBlockRateEnv)
	if err != nil {
		p.finish()
		return err
	}
	if blockRate > 0 {
		runtime.SetBlockProfileRate(blockRate)
		p.blockPath = profilePathWithEnv(filepath.Join(filepath.Dir(p.cpuPath), "block.pprof"), "P2PSTREAM_LABPROFILE_BLOCK")
	}
	mutexFraction, err := labProfileNonNegativeInt(labProfileMutexFractionEnv)
	if err != nil {
		p.finish()
		return err
	}
	if mutexFraction > 0 {
		runtime.SetMutexProfileFraction(mutexFraction)
		p.mutexPath = profilePathWithEnv(filepath.Join(filepath.Dir(p.cpuPath), "mutex.pprof"), "P2PSTREAM_LABPROFILE_MUTEX")
	}
	return nil
}

func labProfileNonNegativeInt(env string) (int, error) {
	raw := strings.TrimSpace(os.Getenv(env))
	if raw == "" {
		return 0, nil
	}
	value, err := strconv.ParseInt(raw, 10, 32)
	if err != nil || value < 0 {
		return 0, fmt.Errorf("%s must be a non-negative integer", env)
	}
	return int(value), nil
}

func profilePathWithEnv(fallback, env string) string {
	if value := strings.TrimSpace(os.Getenv(env)); value != "" {
		return value
	}
	return fallback
}

func (p *labProfile) finish() {
	if p == nil {
		return
	}
	p.once.Do(func() {
		pprof.StopCPUProfile()
		if p.cpuFile != nil {
			if err := p.cpuFile.Close(); err != nil {
				fmt.Fprintf(os.Stderr, "labprofile: close CPU profile: %v\n", err)
			}
		}
		runtime.SetBlockProfileRate(0)
		// Stop CPU sampling before the forced collection so the heap snapshot
		// describes the workload rather than profiler shutdown itself.
		runtime.GC()
		if err := writeLabProfile("heap", p.heapPath, pprof.Lookup("heap")); err != nil {
			fmt.Fprintf(os.Stderr, "labprofile: %v\n", err)
		}
		if err := writeLabProfile("goroutine", p.goroutinePath, pprof.Lookup("goroutine")); err != nil {
			fmt.Fprintf(os.Stderr, "labprofile: %v\n", err)
		}
		if p.blockPath != "" {
			if err := writeLabProfile("block", p.blockPath, pprof.Lookup("block")); err != nil {
				fmt.Fprintf(os.Stderr, "labprofile: %v\n", err)
			}
		}
		if p.mutexPath != "" {
			if err := writeLabProfile("mutex", p.mutexPath, pprof.Lookup("mutex")); err != nil {
				fmt.Fprintf(os.Stderr, "labprofile: %v\n", err)
			}
			runtime.SetMutexProfileFraction(0)
		}
		fmt.Fprintf(os.Stderr, "labprofile finished; heap=%s\n", p.heapPath)
	})
}

func writeLabProfile(name, path string, profile *pprof.Profile) error {
	if profile == nil {
		return fmt.Errorf("%s profile is unavailable", name)
	}
	if err := ensureLabProfileParent(path); err != nil {
		return fmt.Errorf("create %s profile parent: %w", name, err)
	}
	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
	if err != nil {
		return fmt.Errorf("open %s profile %q: %w", name, path, err)
	}
	defer file.Close()
	if err := profile.WriteTo(file, 0); err != nil {
		return fmt.Errorf("write %s profile %q: %w", name, path, err)
	}
	return nil
}

func ensureLabProfileParent(path string) error {
	parent := filepath.Dir(path)
	if parent == "." || parent == "" {
		return nil
	}
	return os.MkdirAll(parent, 0o700)
}