diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-03 23:28:57 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-03 23:28:57 +0300 |
| commit | 2f09915d3da7a23574e1a90fa70eb1af1cdf830a (patch) | |
| tree | 3c46947fd67ac0e20aff84ae2420a4788a8a8c0e | |
initial stuff
| -rw-r--r-- | Magefile.go | 73 | ||||
| -rw-r--r-- | cmd/anelephantinachinashop/main.go | 41 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | internal/config/config.go | 16 | ||||
| -rw-r--r-- | internal/cpu/algorithms.go | 206 | ||||
| -rw-r--r-- | internal/cpu/helpers.go | 21 | ||||
| -rw-r--r-- | internal/cpu/stresser.go | 62 | ||||
| -rw-r--r-- | internal/cpu/stresser_bench_test.go | 114 | ||||
| -rw-r--r-- | internal/cpu/types.go | 45 | ||||
| -rw-r--r-- | internal/cpu/worker.go | 87 | ||||
| -rw-r--r-- | internal/run.go | 7 | ||||
| -rw-r--r-- | internal/version.go | 3 |
13 files changed, 682 insertions, 0 deletions
diff --git a/Magefile.go b/Magefile.go new file mode 100644 index 0000000..015f0f1 --- /dev/null +++ b/Magefile.go @@ -0,0 +1,73 @@ +//go:build mage + +// Package main provides build targets for anelephantinachinashop. +// Targets follow the same style as other projects: Default builds, Test runs tests, +// Bench runs benchmarks, Install copies binary to GOPATH/bin. +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" +) + +const binaryName = "anelephantinachinashop" + +// Default builds the project. +func Default() { + mg.Deps(Build) +} + +// Build compiles the binary. +func Build() error { + return sh.RunV("go", "build", "-o", binaryName, "./cmd/anelephantinachinashop") +} + +// Test runs all unit tests. +func Test() error { + return sh.RunV("go", "test", "./...") +} + +// Bench runs all benchmarks in the cpu package. +func Bench() error { + return sh.RunV("go", "test", "-bench=.", "-benchmem", "./internal/cpu/...") +} + +// Install builds and copies the binary to GOPATH/bin. +func Install() error { + mg.Deps(Build) + + gopath := os.Getenv("GOPATH") + if gopath == "" { + home, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("get home dir: %w", err) + } + gopath = filepath.Join(home, "go") + } + + binDir := filepath.Join(gopath, "bin") + if err := os.MkdirAll(binDir, 0755); err != nil { + return fmt.Errorf("create bin dir: %w", err) + } + + return sh.RunV("cp", "-v", binaryName, binDir) +} + +// Uninstall removes the binary from GOPATH/bin. +func Uninstall() error { + gopath := os.Getenv("GOPATH") + if gopath == "" { + home, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("get home dir: %w", err) + } + gopath = filepath.Join(home, "go") + } + + binPath := filepath.Join(gopath, "bin", binaryName) + return os.Remove(binPath) +} diff --git a/cmd/anelephantinachinashop/main.go b/cmd/anelephantinachinashop/main.go new file mode 100644 index 0000000..398b595 --- /dev/null +++ b/cmd/anelephantinachinashop/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "fmt" + "log" + + "codeberg.org/snonux/anelephantinachinashop/internal" + "codeberg.org/snonux/anelephantinachinashop/internal/config" +) + +func main() { + var conf config.Config + printVersion := flag.Bool("version", false, "Print version") + stressCPU := flag.Bool("cpu", false, "Stress CPU") + stressMemory := flag.Bool("memory", false, "Stress memory") + stressNetwork := flag.Bool("network", false, "Stress network") + flag.Parse() + + if *printVersion { + fmt.Println(internal.Version) + return + } + + if *stressCPU { + conf.CPU = config.CPUStressConfig{} + } + if *stressMemory { + conf.Memory = config.MemoryStressConfig{} + log.Fatal("Mode not yet implemented") + } + // TODO: Also add parallel stressers + if *stressNetwork { + conf.Network = config.NetworkStressConfig{} + log.Fatal("Mode not yet implemented") + } + + if err := internal.Run(conf); err != nil { + log.Fatal(err) + } +} @@ -0,0 +1,5 @@ +module codeberg.org/snonux/anelephantinachinashop + +go 1.26.2 + +require github.com/magefile/mage v1.17.2 @@ -0,0 +1,2 @@ +github.com/magefile/mage v1.17.2 h1:fyXVu1eadI8Ap1HCCNgEhJ5McIWiYhLR8uol64ZZc40= +github.com/magefile/mage v1.17.2/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..6c37916 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,16 @@ +package config + +type CPUStressConfig struct { +} + +type MemoryStressConfig struct { +} + +type NetworkStressConfig struct { +} + +type Config struct { + CPU CPUStressConfig + Memory MemoryStressConfig + Network NetworkStressConfig +} diff --git a/internal/cpu/algorithms.go b/internal/cpu/algorithms.go new file mode 100644 index 0000000..2dd3fe4 --- /dev/null +++ b/internal/cpu/algorithms.go @@ -0,0 +1,206 @@ +// Package cpu provides CPU stress testing with multiple algorithms and chaos modes. +package cpu + +import ( + "context" + "crypto/md5" + "crypto/sha256" + "math" + "sort" +) + +// algorithms.go implements all CPU stress algorithms (prime, matrix, hash, etc.). + +func (s *Stresser) stressPrime(ctx context.Context, n int) { + count := 0 + for i := 2; count < n; i++ { + select { + case <-ctx.Done(): + return + default: + } + if isPrime(i) { + count++ + } + } +} + +func isPrime(n int) bool { + if n < 2 { + return false + } + for i := 2; i*i <= n; i++ { + if n%i == 0 { + return false + } + } + return true +} + +func (s *Stresser) stressMatrix(ctx context.Context, size int) { + if size < 10 { + size = 10 + } + if size > 200 { + size = 200 + } + + a := make([][]float64, size) + b := make([][]float64, size) + for i := range a { + a[i] = make([]float64, size) + b[i] = make([]float64, size) + for j := range a[i] { + a[i][j] = float64(i+j) * 0.5 + b[i][j] = float64(i*j) * 0.3 + } + } + + c := make([][]float64, size) + for i := range c { + c[i] = make([]float64, size) + for j := range c[i] { + select { + case <-ctx.Done(): + return + default: + } + sum := 0.0 + for k := 0; k < size; k++ { + sum += a[i][k] * b[k][j] + } + c[i][j] = sum + } + } +} + +func (s *Stresser) stressHash(ctx context.Context, iterations int) { + data := make([]byte, 1024) + for i := range data { + data[i] = byte(i % 256) + } + + for i := 0; i < iterations; i++ { + select { + case <-ctx.Done(): + return + default: + } + sha256.Sum256(data) + md5.Sum(data) + } +} + +func (s *Stresser) stressBitwise(ctx context.Context, iterations int) { + var result uint64 = 0 + for i := 0; i < iterations*100; i++ { + select { + case <-ctx.Done(): + return + default: + } + result ^= uint64(i) << (i % 64) + result |= result >> 3 + result &= result << 7 + result += result ^ 0x5555555555555555 + result = (result << 13) | (result >> 51) + } + _ = result +} + +func (s *Stresser) stressFloat(ctx context.Context, iterations int) { + x := 1.0 + for i := 0; i < iterations*10; i++ { + select { + case <-ctx.Done(): + return + default: + } + x = math.Sin(x) + math.Cos(x*0.5) + x = math.Sqrt(math.Abs(x)) + math.Exp(x*0.01) + x = math.Atan(x) + math.Log(math.Abs(x)+1) + } + _ = x +} + +func (s *Stresser) stressRecurse(ctx context.Context, n int) { + if n > 35 { + n = 35 + } + _ = fibonacci(n) +} + +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +func (s *Stresser) stressCompress(ctx context.Context, iterations int) { + data := make([]byte, 1024) + for i := range data { + data[i] = byte((i * 7) % 256) + } + + for i := 0; i < iterations; i++ { + select { + case <-ctx.Done(): + return + default: + } + hash := md5.Sum(data) + data = append(data, hash[:]...) + if len(data) > 10240 { + data = data[:1024] + } + } +} + +func (s *Stresser) stressEncrypt(ctx context.Context, iterations int) { + key := make([]byte, 32) + data := make([]byte, 256) + for i := range data { + data[i] = byte(i % 256) + } + + for i := 0; i < iterations; i++ { + select { + case <-ctx.Done(): + return + default: + } + hash := sha256.Sum256(append(key, data...)) + data = hash[:] + } +} + +func (s *Stresser) stressSort(ctx context.Context, size int) { + if size < 100 { + size = 100 + } + if size > 10000 { + size = 10000 + } + + data := make([]int, size) + for i := range data { + data[i] = s.rand.Intn(1000000) + } + + sort.Ints(data) +} + +func (s *Stresser) stressBusy(ctx context.Context, iterations int) { + var sum int64 = 0 + for i := 0; i < iterations*1000; i++ { + select { + case <-ctx.Done(): + return + default: + } + sum += int64(i * i) + sum = sum % 1000000007 + } + _ = sum +} diff --git a/internal/cpu/helpers.go b/internal/cpu/helpers.go new file mode 100644 index 0000000..9fcc6b9 --- /dev/null +++ b/internal/cpu/helpers.go @@ -0,0 +1,21 @@ +// Package cpu provides CPU stress testing with multiple algorithms and chaos modes. +package cpu + +import "time" + +// helpers.go provides utility functions for randomization and timing. + +func (s *Stresser) randomIntensity() int { + s.mu.Lock() + defer s.mu.Unlock() + return s.rand.Intn(s.config.IntensityMax-s.config.IntensityMin+1) + s.config.IntensityMin +} + +func (s *Stresser) getRandomMode() Mode { + return allModes[s.rand.Intn(len(allModes))] +} + +func (s *Stresser) sleepWithJitter(minMs, maxMs int) { + ms := s.rand.Intn(maxMs-minMs+1) + minMs + time.Sleep(time.Duration(ms) * time.Millisecond) +} diff --git a/internal/cpu/stresser.go b/internal/cpu/stresser.go new file mode 100644 index 0000000..906467a --- /dev/null +++ b/internal/cpu/stresser.go @@ -0,0 +1,62 @@ +// Package cpu provides CPU stress testing with multiple algorithms and chaos modes. +package cpu + +import ( + "context" + "math/rand" + "sync" + "time" +) + +// stresser.go contains the main Stresser type, constructor, and lifecycle methods. + +// Stresser uses pointer receivers because it contains a sync.Mutex +// and shared mutable state that must not be copied. +type Stresser struct { + config Config + cancel context.CancelFunc + wg sync.WaitGroup + mu sync.Mutex + current Mode + rand *rand.Rand +} + +func New(cfg Config) *Stresser { + if cfg.Workers <= 0 { + cfg.Workers = 1 + } + if cfg.IntensityMin <= 0 { + cfg.IntensityMin = 100 + } + if cfg.IntensityMax <= 0 { + cfg.IntensityMax = 1000 + } + if cfg.Mode == "" { + cfg.Mode = ModePrime + } + return &Stresser{ + config: cfg, + rand: rand.New(rand.NewSource(time.Now().UnixNano())), + } +} + +func (s *Stresser) Start() { + ctx, cancel := context.WithCancel(context.Background()) + s.cancel = cancel + + s.wg.Add(s.config.Workers) + for i := 0; i < s.config.Workers; i++ { + go s.worker(ctx, i) + } + + if s.config.ChaosEnabled { + go s.chaosController(ctx) + } +} + +func (s *Stresser) Stop() { + if s.cancel != nil { + s.cancel() + } + s.wg.Wait() +} diff --git a/internal/cpu/stresser_bench_test.go b/internal/cpu/stresser_bench_test.go new file mode 100644 index 0000000..042b6f2 --- /dev/null +++ b/internal/cpu/stresser_bench_test.go @@ -0,0 +1,114 @@ +package cpu + +import ( + "context" + "testing" +) + +func benchmarkStress(b *testing.B, stressFunc func(context.Context, int), intensity int) { + b.Helper() + ctx := context.Background() + for i := 0; i < b.N; i++ { + stressFunc(ctx, intensity) + } +} + +func BenchmarkStressPrime(b *testing.B) { + s := New(Config{ + Mode: ModePrime, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressPrime, 100) +} + +func BenchmarkStressMatrix(b *testing.B) { + s := New(Config{ + Mode: ModeMatrix, + Workers: 1, + IntensityMin: 10, + IntensityMax: 50, + }) + benchmarkStress(b, s.stressMatrix, 50) +} + +func BenchmarkStressHash(b *testing.B) { + s := New(Config{ + Mode: ModeHash, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressHash, 100) +} + +func BenchmarkStressBitwise(b *testing.B) { + s := New(Config{ + Mode: ModeBitwise, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressBitwise, 100) +} + +func BenchmarkStressFloat(b *testing.B) { + s := New(Config{ + Mode: ModeFloat, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressFloat, 100) +} + +func BenchmarkStressRecurse(b *testing.B) { + s := New(Config{ + Mode: ModeRecurse, + Workers: 1, + IntensityMin: 10, + IntensityMax: 30, + }) + benchmarkStress(b, s.stressRecurse, 25) +} + +func BenchmarkStressCompress(b *testing.B) { + s := New(Config{ + Mode: ModeCompress, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressCompress, 100) +} + +func BenchmarkStressEncrypt(b *testing.B) { + s := New(Config{ + Mode: ModeEncrypt, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressEncrypt, 100) +} + +func BenchmarkStressSort(b *testing.B) { + s := New(Config{ + Mode: ModeSort, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressSort, 1000) +} + +func BenchmarkStressBusy(b *testing.B) { + s := New(Config{ + Mode: ModeBusy, + Workers: 1, + IntensityMin: 100, + IntensityMax: 1000, + }) + benchmarkStress(b, s.stressBusy, 100) +} diff --git a/internal/cpu/types.go b/internal/cpu/types.go new file mode 100644 index 0000000..58da0a9 --- /dev/null +++ b/internal/cpu/types.go @@ -0,0 +1,45 @@ +// Package cpu provides CPU stress testing with multiple algorithms and chaos modes. +package cpu + +import "time" + +// types.go defines the configuration types and mode constants for CPU stress testing. + +type Mode string + +const ( + ModePrime Mode = "prime" + ModeMatrix Mode = "matrix" + ModeHash Mode = "hash" + ModeBitwise Mode = "bitwise" + ModeFloat Mode = "float" + ModeRecurse Mode = "recurse" + ModeCompress Mode = "compress" + ModeEncrypt Mode = "encrypt" + ModeSort Mode = "sort" + ModeBusy Mode = "busy" + ModeRandom Mode = "random" +) + +var allModes = []Mode{ + ModePrime, + ModeMatrix, + ModeHash, + ModeBitwise, + ModeFloat, + ModeRecurse, + ModeCompress, + ModeEncrypt, + ModeSort, + ModeBusy, +} + +type Config struct { + Mode Mode + Workers int + Duration time.Duration + ChaosEnabled bool + ChaosInterval time.Duration + IntensityMin int + IntensityMax int +} diff --git a/internal/cpu/worker.go b/internal/cpu/worker.go new file mode 100644 index 0000000..06f6812 --- /dev/null +++ b/internal/cpu/worker.go @@ -0,0 +1,87 @@ +// Package cpu provides CPU stress testing with multiple algorithms and chaos modes. +package cpu + +import ( + "context" + "time" +) + +// worker.go implements the worker goroutine loop, chaos controller, and stress dispatching. + +func (s *Stresser) worker(ctx context.Context, id int) { + defer s.wg.Done() + + mode := s.config.Mode + if s.config.ChaosEnabled { + mode = s.getRandomMode() + } + + intensity := s.randomIntensity() + + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + if s.config.ChaosEnabled { + s.mu.Lock() + mode = s.current + s.mu.Unlock() + intensity = s.randomIntensity() + } + + s.executeStress(ctx, mode, intensity) + + if s.config.ChaosEnabled { + s.sleepWithJitter(1, 50) + } + } + } +} + +func (s *Stresser) chaosController(ctx context.Context) { + ticker := time.NewTicker(s.config.ChaosInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + s.mu.Lock() + s.current = s.getRandomMode() + s.mu.Unlock() + } + } +} + +func (s *Stresser) executeStress(ctx context.Context, mode Mode, intensity int) { + switch mode { + case ModePrime: + s.stressPrime(ctx, intensity) + case ModeMatrix: + s.stressMatrix(ctx, intensity) + case ModeHash: + s.stressHash(ctx, intensity) + case ModeBitwise: + s.stressBitwise(ctx, intensity) + case ModeFloat: + s.stressFloat(ctx, intensity) + case ModeRecurse: + s.stressRecurse(ctx, intensity) + case ModeCompress: + s.stressCompress(ctx, intensity) + case ModeEncrypt: + s.stressEncrypt(ctx, intensity) + case ModeSort: + s.stressSort(ctx, intensity) + case ModeBusy: + s.stressBusy(ctx, intensity) + case ModeRandom: + randomMode := allModes[s.rand.Intn(len(allModes))] + s.executeStress(ctx, randomMode, intensity) + } +} diff --git a/internal/run.go b/internal/run.go new file mode 100644 index 0000000..e3bb597 --- /dev/null +++ b/internal/run.go @@ -0,0 +1,7 @@ +package internal + +import "codeberg.org/snonux/anelephantinachinashop/internal/config" + +func Run(conf config.Config) error { + return nil +} diff --git a/internal/version.go b/internal/version.go new file mode 100644 index 0000000..93a42a8 --- /dev/null +++ b/internal/version.go @@ -0,0 +1,3 @@ +package internal + +const Version = "0.0.0" |
