Skip to content

Commit ae777c1

Browse files
authored
Fix performance (#7)
* Update main.go Signed-off-by: Md Imran <[email protected]> * Update main.go Signed-off-by: Md Imran <[email protected]> * Update README.md Signed-off-by: Md Imran <[email protected]> --------- Signed-off-by: Md Imran <[email protected]>
1 parent 38acf53 commit ae777c1

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

README.md

+52-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Build the Docker image using the provided Dockerfile:
3434

3535
```shell
3636
docker build -t k8s-pod-cpu-stressor .
37-
```
37+
```
3838

3939
Run the Docker container, specifying the desired CPU usage, stress duration, and optionally whether to run CPU stress indefinitely:
4040

@@ -56,6 +56,24 @@ The `k8s-pod-cpu-stressor` allows you to specify the desired CPU usage and stres
5656

5757
Adjust these parameters according to your requirements to simulate different CPU load scenarios.
5858

59+
### Kubernetes Resource Requests and Limits
60+
61+
It is recommended to specify Kubernetes resource requests and limits to control the amount of CPU resources consumed by the pod, and to prevent overloading your cluster. For example:
62+
63+
- **Requests**: This defines the minimum amount of CPU that the pod is guaranteed to have.
64+
- **Limits**: This defines the maximum amount of CPU that the pod can use.
65+
66+
Adding requests and limits helps Kubernetes manage resources efficiently and ensures that your cluster remains stable during stress testing.
67+
68+
Example:
69+
70+
```yaml
71+
resources:
72+
requests:
73+
cpu: "100m"
74+
limits:
75+
cpu: "200m"
76+
```
5977
6078
## Check the Public Docker Image
6179
@@ -98,10 +116,42 @@ spec:
98116
cpu: "100m"
99117
```
100118

119+
## Sample Job Manifest
120+
121+
If you want to run the CPU stressor for a fixed duration as a one-time job, you can use the following Kubernetes Job manifest:
122+
123+
```yaml
124+
apiVersion: batch/v1
125+
kind: Job
126+
metadata:
127+
name: cpu-stressor-job
128+
spec:
129+
template:
130+
metadata:
131+
labels:
132+
app: cpu-stressor
133+
spec:
134+
containers:
135+
- name: cpu-stressor
136+
image: narmidm/k8s-pod-cpu-stressor:latest
137+
args:
138+
- "-cpu=0.5"
139+
- "-duration=5m"
140+
resources:
141+
limits:
142+
cpu: "500m"
143+
requests:
144+
cpu: "250m"
145+
restartPolicy: Never
146+
backoffLimit: 3
147+
```
148+
149+
This manifest runs the `k8s-pod-cpu-stressor` as a Kubernetes Job, which will execute the stress test once for 5 minutes and then stop. The `backoffLimit` specifies the number of retries if the job fails.
150+
101151
## Contributing
102152

103153
Contributions are welcome! If you find a bug or have a suggestion, please open an issue or submit a pull request. For major changes, please discuss them first in the issue tracker.
104154

105155
## License
106156

107-
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
157+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

main.go

+33-9
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,81 @@ package main
33
import (
44
"flag"
55
"fmt"
6+
"math/rand"
67
"os"
78
"os/signal"
89
"runtime"
10+
"sync/atomic"
911
"time"
1012
)
1113

1214
func main() {
13-
cpuUsagePtr := flag.Float64("cpu", 0.2, "CPU usage as a fraction (e.g., 0.2 for 200m)")
15+
cpuUsagePtr := flag.Float64("cpu", 0.2, "CPU usage as a fraction (e.g., 0.2 for 20% CPU usage)")
1416
durationPtr := flag.Duration("duration", 10*time.Second, "Duration for the CPU stress (e.g., 10s)")
1517
runForeverPtr := flag.Bool("forever", false, "Run CPU stress indefinitely")
1618
flag.Parse()
1719

1820
numCPU := runtime.NumCPU()
1921
runtime.GOMAXPROCS(numCPU)
2022

23+
// Number of goroutines to use for stressing CPU
2124
numGoroutines := int(float64(numCPU) * (*cpuUsagePtr))
25+
if numGoroutines < 1 {
26+
numGoroutines = 1
27+
}
2228

23-
fmt.Printf("Starting CPU stress with %d goroutines...\n", numGoroutines)
29+
fmt.Printf("Starting CPU stress with %d goroutines targeting %.2f CPU usage...\n", numGoroutines, *cpuUsagePtr)
2430

2531
done := make(chan struct{})
2632

2733
// Capture termination signals
2834
quit := make(chan os.Signal, 1)
2935
signal.Notify(quit, os.Interrupt, os.Kill)
3036

37+
var stopFlag int32
38+
39+
// Improved workload generation
3140
for i := 0; i < numGoroutines; i++ {
3241
go func() {
42+
workDuration := time.Duration(*cpuUsagePtr*1000) * time.Microsecond
43+
idleDuration := time.Duration((1-*cpuUsagePtr)*1000) * time.Microsecond
44+
3345
for {
34-
select {
35-
case <-done:
46+
if atomic.LoadInt32(&stopFlag) == 1 {
3647
return
37-
default:
3848
}
49+
50+
// Busy loop for the specified work duration
51+
endWork := time.Now().Add(workDuration)
52+
for time.Now().Before(endWork) {
53+
// Perform a small computation to keep the CPU active
54+
_ = rand.Float64() * rand.Float64()
55+
}
56+
57+
// Idle for the rest of the interval
58+
time.Sleep(idleDuration)
3959
}
4060
}()
4161
}
4262

4363
go func() {
4464
// Wait for termination signal
4565
<-quit
46-
fmt.Println("Termination signal received. Stopping CPU stress...")
66+
fmt.Println("\nTermination signal received. Stopping CPU stress...")
67+
atomic.StoreInt32(&stopFlag, 1)
4768
close(done)
4869
}()
4970

5071
if !*runForeverPtr {
5172
time.Sleep(*durationPtr)
52-
fmt.Println("CPU stress completed.")
53-
os.Exit(0)
73+
fmt.Println("\nCPU stress completed.")
74+
atomic.StoreInt32(&stopFlag, 1)
75+
close(done)
76+
// Keep the process running to prevent the pod from restarting
77+
select {}
5478
}
5579

5680
// Run stress indefinitely
5781
fmt.Println("CPU stress will run indefinitely. Press Ctrl+C to stop.")
58-
select {}
82+
<-done
5983
}

0 commit comments

Comments
 (0)