summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-03 23:28:57 +0300
committerPaul Buetow <paul@buetow.org>2026-05-03 23:28:57 +0300
commit2f09915d3da7a23574e1a90fa70eb1af1cdf830a (patch)
tree3c46947fd67ac0e20aff84ae2420a4788a8a8c0e
initial stuff
-rw-r--r--Magefile.go73
-rw-r--r--cmd/anelephantinachinashop/main.go41
-rw-r--r--go.mod5
-rw-r--r--go.sum2
-rw-r--r--internal/config/config.go16
-rw-r--r--internal/cpu/algorithms.go206
-rw-r--r--internal/cpu/helpers.go21
-rw-r--r--internal/cpu/stresser.go62
-rw-r--r--internal/cpu/stresser_bench_test.go114
-rw-r--r--internal/cpu/types.go45
-rw-r--r--internal/cpu/worker.go87
-rw-r--r--internal/run.go7
-rw-r--r--internal/version.go3
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)
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..53a1c66
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module codeberg.org/snonux/anelephantinachinashop
+
+go 1.26.2
+
+require github.com/magefile/mage v1.17.2
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a432431
--- /dev/null
+++ b/go.sum
@@ -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"