cpu-loader 0.4.8__tar.gz → 0.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cpu_loader-0.4.8/src/cpu_loader.egg-info → cpu_loader-0.5.4}/PKG-INFO +100 -13
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/README.md +98 -11
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/pyproject.toml +2 -2
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/cpu_loader.py +85 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/cpu_loader_core.c +180 -9
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/main.py +48 -1
- {cpu_loader-0.4.8 → cpu_loader-0.5.4/src/cpu_loader.egg-info}/PKG-INFO +100 -13
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader.egg-info/requires.txt +1 -1
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/LICENSE +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/MANIFEST.in +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/screenshots/01-initial-view.png +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/screenshots/02-with-load.png +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/screenshots/03-live-metrics.png +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/screenshots/04-mobile-view.png +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/setup.cfg +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/setup.py +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/__init__.py +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/__main__.py +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/example.py +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/mqtt_publisher.py +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/static/favicon.svg +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader/templates/index.html +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader.egg-info/SOURCES.txt +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader.egg-info/dependency_links.txt +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader.egg-info/entry_points.txt +0 -0
- {cpu_loader-0.4.8 → cpu_loader-0.5.4}/src/cpu_loader.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cpu-loader
|
|
3
|
-
Version: 0.4
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A tool to generate CPU load on a system with runtime configuration through a WebUI and REST API
|
|
5
5
|
Author-email: the78mole <the78mole@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: fastapi==0.122.0
|
|
29
29
|
Requires-Dist: uvicorn[standard]==0.38.0
|
|
30
|
-
Requires-Dist: pydantic==2.12.
|
|
30
|
+
Requires-Dist: pydantic==2.12.5
|
|
31
31
|
Requires-Dist: requests==2.32.5
|
|
32
32
|
Requires-Dist: psutil>=5.9.0
|
|
33
33
|
Requires-Dist: websockets>=12.0
|
|
@@ -47,11 +47,14 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
47
47
|
|
|
48
48
|
- **🎯 Precise Per-Thread Control**: Set individual CPU load (0-100%) for each core independently
|
|
49
49
|
- **⚡ High Performance**: Native C implementation with pthreads ensures accurate load generation
|
|
50
|
-
-
|
|
50
|
+
- **🧮 Configurable Algorithms**: Choose between 5 different computation types (busy-wait, PI, primes, matrix, fibonacci)
|
|
51
|
+
- **⏱️ Time-Controlled Execution**: All algorithms respect precise timing for accurate load percentages
|
|
52
|
+
- **📊 Real-Time Monitoring**: Live WebSocket updates showing actual CPU usage and temperature via `psutil`
|
|
51
53
|
- **🎛️ Interactive WebUI**: Beautiful gradient interface with sliders and visual feedback
|
|
52
54
|
- **🚀 REST API**: Complete programmatic control for automation and testing
|
|
53
55
|
- **📱 Responsive Design**: Works seamlessly on desktop and mobile devices
|
|
54
56
|
- **🔄 Instant Updates**: Changes take effect immediately with sub-second response time
|
|
57
|
+
- **🌡️ Temperature Monitoring**: Optional CPU temperature tracking with sensor auto-detection
|
|
55
58
|
- 📡 **MQTT Integration**: Publish metrics and settings to MQTT broker for IoT/monitoring systems
|
|
56
59
|
|
|
57
60
|
## 🖼️ Screenshots
|
|
@@ -59,23 +62,23 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
59
62
|
### Interface Screenshots
|
|
60
63
|
<table>
|
|
61
64
|
<tr>
|
|
62
|
-
<td width="
|
|
65
|
+
<td width="40%">
|
|
63
66
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/01-initial-view.png" alt="Initial view with zero load">
|
|
64
67
|
<p align="center"><em>Clean interface showing all CPU threads at idle</em></p>
|
|
65
68
|
</td>
|
|
66
|
-
<td width="
|
|
69
|
+
<td width="60%" rowspan="3" valign="top">
|
|
67
70
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/04-mobile-view.png" alt="Mobile responsive view">
|
|
68
71
|
<p align="center"><em>Fully responsive mobile interface</em></p>
|
|
69
72
|
</td>
|
|
70
73
|
</tr>
|
|
71
74
|
<tr>
|
|
72
|
-
<td width="
|
|
75
|
+
<td width="40%">
|
|
73
76
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/02-with-load.png" alt="Mixed load across threads">
|
|
74
77
|
<p align="center"><em>Different load levels: 50%, 75%, and 25% on individual threads</em></p>
|
|
75
78
|
</td>
|
|
76
79
|
</tr>
|
|
77
80
|
<tr>
|
|
78
|
-
<td width="
|
|
81
|
+
<td width="40%">
|
|
79
82
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/03-live-metrics.png" alt="Live CPU metrics updating">
|
|
80
83
|
<p align="center"><em>Real-time metrics showing actual CPU usage with color-coded bars</em></p>
|
|
81
84
|
</td>
|
|
@@ -144,6 +147,8 @@ uv run src/main.py --help
|
|
|
144
147
|
**Available Options:**
|
|
145
148
|
- `--host HOST`: Host to bind the server to (default: 0.0.0.0)
|
|
146
149
|
- `--port PORT`: Port to bind the server to (default: 8000)
|
|
150
|
+
- `--disable-temperature`: Disable CPU temperature monitoring
|
|
151
|
+
- `--computation-type TYPE`: Set computation algorithm (busy-wait, pi, primes, matrix, fibonacci)
|
|
147
152
|
- `--mqtt-broker-host HOST`: MQTT broker hostname
|
|
148
153
|
- `--mqtt-broker-port PORT`: MQTT broker port (default: 1883)
|
|
149
154
|
- `--mqtt-username USER`: MQTT username
|
|
@@ -151,6 +156,30 @@ uv run src/main.py --help
|
|
|
151
156
|
- `--mqtt-topic-prefix PREFIX`: MQTT topic prefix (default: cpu-loader)
|
|
152
157
|
- `--mqtt-client-id ID`: MQTT client ID (default: cpu-loader)
|
|
153
158
|
|
|
159
|
+
#### Computation Types
|
|
160
|
+
|
|
161
|
+
CPU Loader supports different computation algorithms for load generation with **precise time control**:
|
|
162
|
+
|
|
163
|
+
- **`busy-wait`** (default): Simple busy loop - fastest execution, minimal overhead, most accurate timing
|
|
164
|
+
- **`pi`**: PI calculation using Leibniz formula - moderate computational intensity, mathematical workload
|
|
165
|
+
- **`primes`**: Prime number finding - variable computational load, cryptographic-style operations
|
|
166
|
+
- **`matrix`**: 4x4 matrix multiplication - consistent computational patterns, linear algebra operations
|
|
167
|
+
- **`fibonacci`**: Lightweight mathematical operations - balanced computational load with micro-pauses
|
|
168
|
+
|
|
169
|
+
All algorithms are **time-controlled** to ensure accurate load percentages. The system uses 10ms cycles with frequent timing checks to maintain precise CPU utilization.
|
|
170
|
+
|
|
171
|
+
**Examples:**
|
|
172
|
+
```bash
|
|
173
|
+
# Use PI calculation for CPU load
|
|
174
|
+
uv run cpu-loader --computation-type pi
|
|
175
|
+
|
|
176
|
+
# Use prime number calculation
|
|
177
|
+
uv run cpu-loader --computation-type primes --port 8001
|
|
178
|
+
|
|
179
|
+
# Use matrix multiplication
|
|
180
|
+
uv run cpu-loader --computation-type matrix
|
|
181
|
+
```
|
|
182
|
+
|
|
154
183
|
### WebUI
|
|
155
184
|
|
|
156
185
|
Open your browser and navigate to `http://localhost:8000`
|
|
@@ -202,6 +231,26 @@ curl -X POST http://localhost:8000/api/threads \
|
|
|
202
231
|
-d '{"num_threads": 8}'
|
|
203
232
|
```
|
|
204
233
|
|
|
234
|
+
#### Get Computation Type
|
|
235
|
+
```bash
|
|
236
|
+
curl http://localhost:8000/api/computation-type
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Response:
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"computation_type": "pi",
|
|
243
|
+
"available_types": ["busy-wait", "pi", "primes", "matrix", "fibonacci"]
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Set Computation Type
|
|
248
|
+
```bash
|
|
249
|
+
curl -X PUT http://localhost:8000/api/computation-type \
|
|
250
|
+
-H "Content-Type: application/json" \
|
|
251
|
+
-d '{"computation_type": "fibonacci"}'
|
|
252
|
+
```
|
|
253
|
+
|
|
205
254
|
## API Documentation
|
|
206
255
|
|
|
207
256
|
Once the server is running, visit `http://localhost:8000/docs` for interactive API documentation powered by Swagger UI.
|
|
@@ -307,6 +356,31 @@ The example demonstrates:
|
|
|
307
356
|
- Individual thread control
|
|
308
357
|
- Resetting to idle
|
|
309
358
|
|
|
359
|
+
### Computation Types Demo
|
|
360
|
+
|
|
361
|
+
A comprehensive demo script is available in `examples/computation_types_demo.py` to test all computation algorithms:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
# Start the server
|
|
365
|
+
uv run cpu-loader
|
|
366
|
+
|
|
367
|
+
# In another terminal, run the demo (tests all computation types)
|
|
368
|
+
python examples/computation_types_demo.py
|
|
369
|
+
|
|
370
|
+
# Test specific computation types only
|
|
371
|
+
python examples/computation_types_demo.py --types pi fibonacci
|
|
372
|
+
|
|
373
|
+
# Custom load and duration
|
|
374
|
+
python examples/computation_types_demo.py --load 50 --duration 15
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
The demo script:
|
|
378
|
+
|
|
379
|
+
- Tests each computation type systematically
|
|
380
|
+
- Monitors actual CPU usage vs. target load
|
|
381
|
+
- Provides performance comparisons between algorithms
|
|
382
|
+
- Shows timing accuracy for each computation method
|
|
383
|
+
|
|
310
384
|
## Architecture
|
|
311
385
|
|
|
312
386
|
- **src/cpu_loader_core.c**: High-performance C implementation using pthreads for CPU load generation
|
|
@@ -327,13 +401,22 @@ The example demonstrates:
|
|
|
327
401
|
|
|
328
402
|
## Use Cases
|
|
329
403
|
|
|
330
|
-
- **Performance Testing**: Test application behavior under various CPU loads
|
|
331
|
-
- **Stress Testing**: Validate system stability under high CPU utilization
|
|
332
|
-
- **Thermal Testing**:
|
|
333
|
-
- **Power Consumption Analysis**:
|
|
334
|
-
- **Benchmarking**: Create reproducible load scenarios
|
|
404
|
+
- **Performance Testing**: Test application behavior under various CPU loads and computation types
|
|
405
|
+
- **Stress Testing**: Validate system stability under high CPU utilization with different algorithms
|
|
406
|
+
- **Thermal Testing**: Use fibonacci or matrix computations for maximum heat generation
|
|
407
|
+
- **Power Consumption Analysis**: Compare power usage across different computation algorithms
|
|
408
|
+
- **Benchmarking**: Create reproducible load scenarios with specific computation patterns
|
|
409
|
+
- **Algorithm Testing**: Test cache performance (matrix), mathematical units (pi), or crypto operations (primes)
|
|
335
410
|
- **IoT Integration**: Integrate with Home Assistant, Node-RED, or other MQTT-based systems
|
|
336
|
-
- **Monitoring**: Feed CPU metrics into monitoring dashboards via MQTT
|
|
411
|
+
- **Monitoring**: Feed CPU metrics and temperature data into monitoring dashboards via MQTT
|
|
412
|
+
|
|
413
|
+
### Computation Algorithm Use Cases
|
|
414
|
+
|
|
415
|
+
- **`busy-wait`**: Baseline testing, pure timing validation, minimal computational overhead
|
|
416
|
+
- **`pi`**: Mathematical processing benchmarks, floating-point unit testing
|
|
417
|
+
- **`primes`**: Cryptographic algorithm simulation, integer arithmetic testing
|
|
418
|
+
- **`matrix`**: Linear algebra workloads, cache hierarchy testing, SIMD instruction testing
|
|
419
|
+
- **`fibonacci`**: Balanced computational load for general stress testing
|
|
337
420
|
|
|
338
421
|
## Development
|
|
339
422
|
|
|
@@ -363,10 +446,13 @@ Versions are automatically determined based on commit messages:
|
|
|
363
446
|
|
|
364
447
|
- **Patch bump** (0.0.X): Every commit to main
|
|
365
448
|
- **Minor bump** (0.X.0): Commits prefixed with `feat:`
|
|
449
|
+
|
|
366
450
|
```bash
|
|
367
451
|
git commit -m "feat: add new CPU monitoring feature"
|
|
368
452
|
```
|
|
453
|
+
|
|
369
454
|
- **Major bump** (X.0.0): Commits with `major:`, `breaking:`, or `BREAKING CHANGE:`
|
|
455
|
+
|
|
370
456
|
```bash
|
|
371
457
|
git commit -m "major: redesign API interface"
|
|
372
458
|
git commit -m "breaking: remove deprecated endpoints"
|
|
@@ -375,6 +461,7 @@ Versions are automatically determined based on commit messages:
|
|
|
375
461
|
#### Release Process
|
|
376
462
|
|
|
377
463
|
1. **Commit and push to main**:
|
|
464
|
+
|
|
378
465
|
```bash
|
|
379
466
|
git add .
|
|
380
467
|
git commit -m "feat: add WebSocket support"
|
|
@@ -11,11 +11,14 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
11
11
|
|
|
12
12
|
- **🎯 Precise Per-Thread Control**: Set individual CPU load (0-100%) for each core independently
|
|
13
13
|
- **⚡ High Performance**: Native C implementation with pthreads ensures accurate load generation
|
|
14
|
-
-
|
|
14
|
+
- **🧮 Configurable Algorithms**: Choose between 5 different computation types (busy-wait, PI, primes, matrix, fibonacci)
|
|
15
|
+
- **⏱️ Time-Controlled Execution**: All algorithms respect precise timing for accurate load percentages
|
|
16
|
+
- **📊 Real-Time Monitoring**: Live WebSocket updates showing actual CPU usage and temperature via `psutil`
|
|
15
17
|
- **🎛️ Interactive WebUI**: Beautiful gradient interface with sliders and visual feedback
|
|
16
18
|
- **🚀 REST API**: Complete programmatic control for automation and testing
|
|
17
19
|
- **📱 Responsive Design**: Works seamlessly on desktop and mobile devices
|
|
18
20
|
- **🔄 Instant Updates**: Changes take effect immediately with sub-second response time
|
|
21
|
+
- **🌡️ Temperature Monitoring**: Optional CPU temperature tracking with sensor auto-detection
|
|
19
22
|
- 📡 **MQTT Integration**: Publish metrics and settings to MQTT broker for IoT/monitoring systems
|
|
20
23
|
|
|
21
24
|
## 🖼️ Screenshots
|
|
@@ -23,23 +26,23 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
23
26
|
### Interface Screenshots
|
|
24
27
|
<table>
|
|
25
28
|
<tr>
|
|
26
|
-
<td width="
|
|
29
|
+
<td width="40%">
|
|
27
30
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/01-initial-view.png" alt="Initial view with zero load">
|
|
28
31
|
<p align="center"><em>Clean interface showing all CPU threads at idle</em></p>
|
|
29
32
|
</td>
|
|
30
|
-
<td width="
|
|
33
|
+
<td width="60%" rowspan="3" valign="top">
|
|
31
34
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/04-mobile-view.png" alt="Mobile responsive view">
|
|
32
35
|
<p align="center"><em>Fully responsive mobile interface</em></p>
|
|
33
36
|
</td>
|
|
34
37
|
</tr>
|
|
35
38
|
<tr>
|
|
36
|
-
<td width="
|
|
39
|
+
<td width="40%">
|
|
37
40
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/02-with-load.png" alt="Mixed load across threads">
|
|
38
41
|
<p align="center"><em>Different load levels: 50%, 75%, and 25% on individual threads</em></p>
|
|
39
42
|
</td>
|
|
40
43
|
</tr>
|
|
41
44
|
<tr>
|
|
42
|
-
<td width="
|
|
45
|
+
<td width="40%">
|
|
43
46
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/03-live-metrics.png" alt="Live CPU metrics updating">
|
|
44
47
|
<p align="center"><em>Real-time metrics showing actual CPU usage with color-coded bars</em></p>
|
|
45
48
|
</td>
|
|
@@ -108,6 +111,8 @@ uv run src/main.py --help
|
|
|
108
111
|
**Available Options:**
|
|
109
112
|
- `--host HOST`: Host to bind the server to (default: 0.0.0.0)
|
|
110
113
|
- `--port PORT`: Port to bind the server to (default: 8000)
|
|
114
|
+
- `--disable-temperature`: Disable CPU temperature monitoring
|
|
115
|
+
- `--computation-type TYPE`: Set computation algorithm (busy-wait, pi, primes, matrix, fibonacci)
|
|
111
116
|
- `--mqtt-broker-host HOST`: MQTT broker hostname
|
|
112
117
|
- `--mqtt-broker-port PORT`: MQTT broker port (default: 1883)
|
|
113
118
|
- `--mqtt-username USER`: MQTT username
|
|
@@ -115,6 +120,30 @@ uv run src/main.py --help
|
|
|
115
120
|
- `--mqtt-topic-prefix PREFIX`: MQTT topic prefix (default: cpu-loader)
|
|
116
121
|
- `--mqtt-client-id ID`: MQTT client ID (default: cpu-loader)
|
|
117
122
|
|
|
123
|
+
#### Computation Types
|
|
124
|
+
|
|
125
|
+
CPU Loader supports different computation algorithms for load generation with **precise time control**:
|
|
126
|
+
|
|
127
|
+
- **`busy-wait`** (default): Simple busy loop - fastest execution, minimal overhead, most accurate timing
|
|
128
|
+
- **`pi`**: PI calculation using Leibniz formula - moderate computational intensity, mathematical workload
|
|
129
|
+
- **`primes`**: Prime number finding - variable computational load, cryptographic-style operations
|
|
130
|
+
- **`matrix`**: 4x4 matrix multiplication - consistent computational patterns, linear algebra operations
|
|
131
|
+
- **`fibonacci`**: Lightweight mathematical operations - balanced computational load with micro-pauses
|
|
132
|
+
|
|
133
|
+
All algorithms are **time-controlled** to ensure accurate load percentages. The system uses 10ms cycles with frequent timing checks to maintain precise CPU utilization.
|
|
134
|
+
|
|
135
|
+
**Examples:**
|
|
136
|
+
```bash
|
|
137
|
+
# Use PI calculation for CPU load
|
|
138
|
+
uv run cpu-loader --computation-type pi
|
|
139
|
+
|
|
140
|
+
# Use prime number calculation
|
|
141
|
+
uv run cpu-loader --computation-type primes --port 8001
|
|
142
|
+
|
|
143
|
+
# Use matrix multiplication
|
|
144
|
+
uv run cpu-loader --computation-type matrix
|
|
145
|
+
```
|
|
146
|
+
|
|
118
147
|
### WebUI
|
|
119
148
|
|
|
120
149
|
Open your browser and navigate to `http://localhost:8000`
|
|
@@ -166,6 +195,26 @@ curl -X POST http://localhost:8000/api/threads \
|
|
|
166
195
|
-d '{"num_threads": 8}'
|
|
167
196
|
```
|
|
168
197
|
|
|
198
|
+
#### Get Computation Type
|
|
199
|
+
```bash
|
|
200
|
+
curl http://localhost:8000/api/computation-type
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Response:
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"computation_type": "pi",
|
|
207
|
+
"available_types": ["busy-wait", "pi", "primes", "matrix", "fibonacci"]
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### Set Computation Type
|
|
212
|
+
```bash
|
|
213
|
+
curl -X PUT http://localhost:8000/api/computation-type \
|
|
214
|
+
-H "Content-Type: application/json" \
|
|
215
|
+
-d '{"computation_type": "fibonacci"}'
|
|
216
|
+
```
|
|
217
|
+
|
|
169
218
|
## API Documentation
|
|
170
219
|
|
|
171
220
|
Once the server is running, visit `http://localhost:8000/docs` for interactive API documentation powered by Swagger UI.
|
|
@@ -271,6 +320,31 @@ The example demonstrates:
|
|
|
271
320
|
- Individual thread control
|
|
272
321
|
- Resetting to idle
|
|
273
322
|
|
|
323
|
+
### Computation Types Demo
|
|
324
|
+
|
|
325
|
+
A comprehensive demo script is available in `examples/computation_types_demo.py` to test all computation algorithms:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Start the server
|
|
329
|
+
uv run cpu-loader
|
|
330
|
+
|
|
331
|
+
# In another terminal, run the demo (tests all computation types)
|
|
332
|
+
python examples/computation_types_demo.py
|
|
333
|
+
|
|
334
|
+
# Test specific computation types only
|
|
335
|
+
python examples/computation_types_demo.py --types pi fibonacci
|
|
336
|
+
|
|
337
|
+
# Custom load and duration
|
|
338
|
+
python examples/computation_types_demo.py --load 50 --duration 15
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
The demo script:
|
|
342
|
+
|
|
343
|
+
- Tests each computation type systematically
|
|
344
|
+
- Monitors actual CPU usage vs. target load
|
|
345
|
+
- Provides performance comparisons between algorithms
|
|
346
|
+
- Shows timing accuracy for each computation method
|
|
347
|
+
|
|
274
348
|
## Architecture
|
|
275
349
|
|
|
276
350
|
- **src/cpu_loader_core.c**: High-performance C implementation using pthreads for CPU load generation
|
|
@@ -291,13 +365,22 @@ The example demonstrates:
|
|
|
291
365
|
|
|
292
366
|
## Use Cases
|
|
293
367
|
|
|
294
|
-
- **Performance Testing**: Test application behavior under various CPU loads
|
|
295
|
-
- **Stress Testing**: Validate system stability under high CPU utilization
|
|
296
|
-
- **Thermal Testing**:
|
|
297
|
-
- **Power Consumption Analysis**:
|
|
298
|
-
- **Benchmarking**: Create reproducible load scenarios
|
|
368
|
+
- **Performance Testing**: Test application behavior under various CPU loads and computation types
|
|
369
|
+
- **Stress Testing**: Validate system stability under high CPU utilization with different algorithms
|
|
370
|
+
- **Thermal Testing**: Use fibonacci or matrix computations for maximum heat generation
|
|
371
|
+
- **Power Consumption Analysis**: Compare power usage across different computation algorithms
|
|
372
|
+
- **Benchmarking**: Create reproducible load scenarios with specific computation patterns
|
|
373
|
+
- **Algorithm Testing**: Test cache performance (matrix), mathematical units (pi), or crypto operations (primes)
|
|
299
374
|
- **IoT Integration**: Integrate with Home Assistant, Node-RED, or other MQTT-based systems
|
|
300
|
-
- **Monitoring**: Feed CPU metrics into monitoring dashboards via MQTT
|
|
375
|
+
- **Monitoring**: Feed CPU metrics and temperature data into monitoring dashboards via MQTT
|
|
376
|
+
|
|
377
|
+
### Computation Algorithm Use Cases
|
|
378
|
+
|
|
379
|
+
- **`busy-wait`**: Baseline testing, pure timing validation, minimal computational overhead
|
|
380
|
+
- **`pi`**: Mathematical processing benchmarks, floating-point unit testing
|
|
381
|
+
- **`primes`**: Cryptographic algorithm simulation, integer arithmetic testing
|
|
382
|
+
- **`matrix`**: Linear algebra workloads, cache hierarchy testing, SIMD instruction testing
|
|
383
|
+
- **`fibonacci`**: Balanced computational load for general stress testing
|
|
301
384
|
|
|
302
385
|
## Development
|
|
303
386
|
|
|
@@ -327,10 +410,13 @@ Versions are automatically determined based on commit messages:
|
|
|
327
410
|
|
|
328
411
|
- **Patch bump** (0.0.X): Every commit to main
|
|
329
412
|
- **Minor bump** (0.X.0): Commits prefixed with `feat:`
|
|
413
|
+
|
|
330
414
|
```bash
|
|
331
415
|
git commit -m "feat: add new CPU monitoring feature"
|
|
332
416
|
```
|
|
417
|
+
|
|
333
418
|
- **Major bump** (X.0.0): Commits with `major:`, `breaking:`, or `BREAKING CHANGE:`
|
|
419
|
+
|
|
334
420
|
```bash
|
|
335
421
|
git commit -m "major: redesign API interface"
|
|
336
422
|
git commit -m "breaking: remove deprecated endpoints"
|
|
@@ -339,6 +425,7 @@ Versions are automatically determined based on commit messages:
|
|
|
339
425
|
#### Release Process
|
|
340
426
|
|
|
341
427
|
1. **Commit and push to main**:
|
|
428
|
+
|
|
342
429
|
```bash
|
|
343
430
|
git add .
|
|
344
431
|
git commit -m "feat: add WebSocket support"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cpu-loader"
|
|
3
|
-
version = "0.4
|
|
3
|
+
version = "0.5.4"
|
|
4
4
|
description = "A tool to generate CPU load on a system with runtime configuration through a WebUI and REST API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
dependencies = [
|
|
28
28
|
"fastapi==0.122.0",
|
|
29
29
|
"uvicorn[standard]==0.38.0",
|
|
30
|
-
"pydantic==2.12.
|
|
30
|
+
"pydantic==2.12.5",
|
|
31
31
|
"requests==2.32.5",
|
|
32
32
|
"psutil>=5.9.0",
|
|
33
33
|
"websockets>=12.0",
|
|
@@ -16,6 +16,52 @@ except ImportError:
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
class ComputationType:
|
|
20
|
+
"""Enumeration for different computation types."""
|
|
21
|
+
|
|
22
|
+
BUSY_WAIT = 0
|
|
23
|
+
PI_CALCULATION = 1
|
|
24
|
+
PRIME_NUMBERS = 2
|
|
25
|
+
MATRIX_MULTIPLY = 3
|
|
26
|
+
FIBONACCI = 4
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_string(cls, compute_str: str) -> int:
|
|
30
|
+
"""Convert string representation to computation type integer."""
|
|
31
|
+
compute_map = {
|
|
32
|
+
"busy-wait": cls.BUSY_WAIT,
|
|
33
|
+
"pi": cls.PI_CALCULATION,
|
|
34
|
+
"primes": cls.PRIME_NUMBERS,
|
|
35
|
+
"matrix": cls.MATRIX_MULTIPLY,
|
|
36
|
+
"fibonacci": cls.FIBONACCI,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
compute_str = compute_str.lower().strip()
|
|
40
|
+
if compute_str not in compute_map:
|
|
41
|
+
available = ", ".join(compute_map.keys())
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"Invalid computation type '{compute_str}'. Available: {available}"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return compute_map[compute_str]
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def to_string(cls, compute_type: int) -> str:
|
|
50
|
+
"""Convert computation type integer to string representation."""
|
|
51
|
+
type_map = {
|
|
52
|
+
cls.BUSY_WAIT: "busy-wait",
|
|
53
|
+
cls.PI_CALCULATION: "pi",
|
|
54
|
+
cls.PRIME_NUMBERS: "primes",
|
|
55
|
+
cls.MATRIX_MULTIPLY: "matrix",
|
|
56
|
+
cls.FIBONACCI: "fibonacci",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if compute_type not in type_map:
|
|
60
|
+
raise ValueError(f"Invalid computation type {compute_type}")
|
|
61
|
+
|
|
62
|
+
return type_map[compute_type]
|
|
63
|
+
|
|
64
|
+
|
|
19
65
|
class CPULoader:
|
|
20
66
|
"""Manages CPU load generation across multiple threads using C extension."""
|
|
21
67
|
|
|
@@ -102,6 +148,45 @@ class CPULoader:
|
|
|
102
148
|
self.num_threads = num_threads
|
|
103
149
|
cpu_loader_core.init_loader(num_threads)
|
|
104
150
|
|
|
151
|
+
def set_computation_type(self, compute_type: int):
|
|
152
|
+
"""
|
|
153
|
+
Set the computation type for CPU load generation.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
compute_type: Computation type (use ComputationType constants)
|
|
157
|
+
"""
|
|
158
|
+
cpu_loader_core.set_computation_type(compute_type)
|
|
159
|
+
|
|
160
|
+
def get_computation_type(self) -> int:
|
|
161
|
+
"""
|
|
162
|
+
Get the current computation type.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Current computation type integer
|
|
166
|
+
"""
|
|
167
|
+
return cpu_loader_core.get_computation_type()
|
|
168
|
+
|
|
169
|
+
def set_computation_type_from_string(self, compute_str: str):
|
|
170
|
+
"""
|
|
171
|
+
Set the computation type from string representation.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
compute_str: Computation type as string (e.g., 'pi', 'primes',
|
|
175
|
+
'matrix', 'fibonacci', 'busy-wait')
|
|
176
|
+
"""
|
|
177
|
+
compute_type = ComputationType.from_string(compute_str)
|
|
178
|
+
self.set_computation_type(compute_type)
|
|
179
|
+
|
|
180
|
+
def get_computation_type_string(self) -> str:
|
|
181
|
+
"""
|
|
182
|
+
Get the current computation type as string.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Current computation type as string
|
|
186
|
+
"""
|
|
187
|
+
compute_type = self.get_computation_type()
|
|
188
|
+
return ComputationType.to_string(compute_type)
|
|
189
|
+
|
|
105
190
|
def shutdown(self):
|
|
106
191
|
"""Shutdown all threads."""
|
|
107
192
|
cpu_loader_core.shutdown()
|
|
@@ -6,7 +6,16 @@
|
|
|
6
6
|
#include <stdbool.h>
|
|
7
7
|
#include <stdio.h>
|
|
8
8
|
|
|
9
|
-
#define CYCLE_TIME_NS
|
|
9
|
+
#define CYCLE_TIME_NS 10000000L // 10ms in nanoseconds for better responsiveness
|
|
10
|
+
|
|
11
|
+
// Computation types for busy-wait
|
|
12
|
+
typedef enum {
|
|
13
|
+
COMPUTE_BUSY_WAIT = 0,
|
|
14
|
+
COMPUTE_PI_CALCULATION = 1,
|
|
15
|
+
COMPUTE_PRIME_NUMBERS = 2,
|
|
16
|
+
COMPUTE_MATRIX_MULTIPLY = 3,
|
|
17
|
+
COMPUTE_FIBONACCI = 4
|
|
18
|
+
} ComputationType;
|
|
10
19
|
|
|
11
20
|
typedef struct {
|
|
12
21
|
pthread_t thread;
|
|
@@ -14,11 +23,13 @@ typedef struct {
|
|
|
14
23
|
double load; // 0.0 to 1.0
|
|
15
24
|
bool running;
|
|
16
25
|
bool stop;
|
|
26
|
+
ComputationType compute_type;
|
|
17
27
|
pthread_mutex_t lock;
|
|
18
28
|
} WorkerThread;
|
|
19
29
|
|
|
20
30
|
static WorkerThread *workers = NULL;
|
|
21
31
|
static int num_threads = 0;
|
|
32
|
+
static ComputationType global_compute_type = COMPUTE_BUSY_WAIT;
|
|
22
33
|
static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
23
34
|
|
|
24
35
|
// High-resolution timer
|
|
@@ -28,12 +39,131 @@ static inline long long get_time_ns(void) {
|
|
|
28
39
|
return (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec;
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
//
|
|
32
|
-
static
|
|
42
|
+
// Time-controlled PI calculation using Leibniz formula
|
|
43
|
+
static void calculate_pi_timed(long long duration_ns) {
|
|
33
44
|
long long start = get_time_ns();
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
double pi = 0.0;
|
|
46
|
+
int i = 0;
|
|
47
|
+
|
|
48
|
+
// Check time every 100 iterations for better responsiveness
|
|
49
|
+
while ((get_time_ns() - start) < duration_ns) {
|
|
50
|
+
for (int batch = 0; batch < 100 && (get_time_ns() - start) < duration_ns; batch++) {
|
|
51
|
+
pi += (i % 2 == 0 ? 1.0 : -1.0) / (2 * i + 1);
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Prime number checking (time-controlled)
|
|
58
|
+
static bool is_prime_quick(long long n) {
|
|
59
|
+
if (n < 2) return false;
|
|
60
|
+
if (n == 2) return true;
|
|
61
|
+
if (n % 2 == 0) return false;
|
|
62
|
+
|
|
63
|
+
for (long long i = 3; i * i <= n; i += 2) {
|
|
64
|
+
if (n % i == 0) return false;
|
|
36
65
|
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Time-controlled prime number finding
|
|
70
|
+
static void find_primes_timed(long long duration_ns) {
|
|
71
|
+
long long start = get_time_ns();
|
|
72
|
+
long long n = 1000; // Start from a reasonable number
|
|
73
|
+
|
|
74
|
+
while ((get_time_ns() - start) < duration_ns) {
|
|
75
|
+
// Process numbers one by one with frequent time checks
|
|
76
|
+
is_prime_quick(n);
|
|
77
|
+
n++;
|
|
78
|
+
if (n > 100000) n = 1000; // Reset to avoid overflow
|
|
79
|
+
|
|
80
|
+
// Check time more frequently for better control
|
|
81
|
+
if ((n % 50) == 0 && (get_time_ns() - start) >= duration_ns) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Simple matrix multiplication (4x4 matrices) - time controlled
|
|
88
|
+
static void matrix_multiply_timed(long long duration_ns) {
|
|
89
|
+
long long start = get_time_ns();
|
|
90
|
+
double a[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
|
|
91
|
+
double b[4][4] = {{16,15,14,13},{12,11,10,9},{8,7,6,5},{4,3,2,1}};
|
|
92
|
+
double result[4][4];
|
|
93
|
+
|
|
94
|
+
while ((get_time_ns() - start) < duration_ns) {
|
|
95
|
+
// Perform matrix multiplication with frequent time checks
|
|
96
|
+
for (int i = 0; i < 4; i++) {
|
|
97
|
+
for (int j = 0; j < 4; j++) {
|
|
98
|
+
result[i][j] = 0;
|
|
99
|
+
for (int k = 0; k < 4; k++) {
|
|
100
|
+
result[i][j] += a[i][k] * b[k][j];
|
|
101
|
+
}
|
|
102
|
+
// Check time after each element calculation
|
|
103
|
+
if ((get_time_ns() - start) >= duration_ns) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Vary matrices slightly to prevent optimization
|
|
109
|
+
a[0][0] = result[0][0] / 1000000.0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Time-controlled lightweight computational work (simplified approach)
|
|
114
|
+
static void fibonacci_timed(long long duration_ns) {
|
|
115
|
+
long long start = get_time_ns();
|
|
116
|
+
volatile double result = 0.0; // Use volatile to prevent optimization
|
|
117
|
+
int counter = 0;
|
|
118
|
+
|
|
119
|
+
while ((get_time_ns() - start) < duration_ns) {
|
|
120
|
+
// Perform lightweight mathematical operations
|
|
121
|
+
for (int i = 0; i < 100 && (get_time_ns() - start) < duration_ns; i++) {
|
|
122
|
+
result += counter * 1.1 + 0.5;
|
|
123
|
+
counter = (counter + 1) % 1000;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Small computational pause
|
|
127
|
+
struct timespec tiny_pause = {0, 5000}; // 5 microseconds
|
|
128
|
+
nanosleep(&tiny_pause, NULL);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Perform computation based on type for specified duration
|
|
133
|
+
static void perform_computation(ComputationType type, long long duration_ns) {
|
|
134
|
+
switch (type) {
|
|
135
|
+
case COMPUTE_PI_CALCULATION:
|
|
136
|
+
calculate_pi_timed(duration_ns);
|
|
137
|
+
break;
|
|
138
|
+
|
|
139
|
+
case COMPUTE_PRIME_NUMBERS:
|
|
140
|
+
find_primes_timed(duration_ns);
|
|
141
|
+
break;
|
|
142
|
+
|
|
143
|
+
case COMPUTE_MATRIX_MULTIPLY:
|
|
144
|
+
matrix_multiply_timed(duration_ns);
|
|
145
|
+
break;
|
|
146
|
+
|
|
147
|
+
case COMPUTE_FIBONACCI:
|
|
148
|
+
fibonacci_timed(duration_ns);
|
|
149
|
+
break;
|
|
150
|
+
|
|
151
|
+
case COMPUTE_BUSY_WAIT:
|
|
152
|
+
default:
|
|
153
|
+
// Original busy-wait implementation
|
|
154
|
+
{
|
|
155
|
+
long long start = get_time_ns();
|
|
156
|
+
while ((get_time_ns() - start) < duration_ns) {
|
|
157
|
+
// Busy loop
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Busy-wait for specified nanoseconds (backward compatibility)
|
|
165
|
+
static inline void busy_wait_ns(long long ns) {
|
|
166
|
+
perform_computation(COMPUTE_BUSY_WAIT, ns);
|
|
37
167
|
}
|
|
38
168
|
|
|
39
169
|
static void *worker_thread(void *arg) {
|
|
@@ -44,6 +174,7 @@ static void *worker_thread(void *arg) {
|
|
|
44
174
|
|
|
45
175
|
pthread_mutex_lock(&worker->lock);
|
|
46
176
|
double load = worker->load;
|
|
177
|
+
ComputationType compute_type = worker->compute_type;
|
|
47
178
|
pthread_mutex_unlock(&worker->lock);
|
|
48
179
|
|
|
49
180
|
if (load <= 0.0) {
|
|
@@ -51,14 +182,14 @@ static void *worker_thread(void *arg) {
|
|
|
51
182
|
struct timespec sleep_time = {0, CYCLE_TIME_NS};
|
|
52
183
|
nanosleep(&sleep_time, NULL);
|
|
53
184
|
} else if (load >= 1.0) {
|
|
54
|
-
// 100% load,
|
|
55
|
-
|
|
185
|
+
// 100% load, perform computation for the entire cycle
|
|
186
|
+
perform_computation(compute_type, CYCLE_TIME_NS);
|
|
56
187
|
} else {
|
|
57
188
|
// Partial load
|
|
58
189
|
long long work_time_ns = (long long)(load * CYCLE_TIME_NS);
|
|
59
190
|
|
|
60
|
-
//
|
|
61
|
-
|
|
191
|
+
// Perform computation for work time
|
|
192
|
+
perform_computation(compute_type, work_time_ns);
|
|
62
193
|
|
|
63
194
|
// Sleep for the rest of the cycle
|
|
64
195
|
long long elapsed = get_time_ns() - cycle_start;
|
|
@@ -114,6 +245,7 @@ static PyObject *init_loader(PyObject *self, PyObject *args) {
|
|
|
114
245
|
workers[i].load = 0.0;
|
|
115
246
|
workers[i].running = false;
|
|
116
247
|
workers[i].stop = false;
|
|
248
|
+
workers[i].compute_type = global_compute_type;
|
|
117
249
|
pthread_mutex_init(&workers[i].lock, NULL);
|
|
118
250
|
|
|
119
251
|
if (pthread_create(&workers[i].thread, NULL, worker_thread, &workers[i]) != 0) {
|
|
@@ -217,6 +349,43 @@ static PyObject *get_num_threads(PyObject *self, PyObject *args) {
|
|
|
217
349
|
return PyLong_FromLong(n);
|
|
218
350
|
}
|
|
219
351
|
|
|
352
|
+
// Set computation type
|
|
353
|
+
static PyObject *set_computation_type(PyObject *self, PyObject *args) {
|
|
354
|
+
int comp_type;
|
|
355
|
+
|
|
356
|
+
if (!PyArg_ParseTuple(args, "i", &comp_type)) {
|
|
357
|
+
return NULL;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (comp_type < 0 || comp_type > COMPUTE_FIBONACCI) {
|
|
361
|
+
PyErr_SetString(PyExc_ValueError, "Invalid computation type");
|
|
362
|
+
return NULL;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
pthread_mutex_lock(&global_lock);
|
|
366
|
+
global_compute_type = (ComputationType)comp_type;
|
|
367
|
+
|
|
368
|
+
// Update all existing workers
|
|
369
|
+
for (int i = 0; i < num_threads; i++) {
|
|
370
|
+
pthread_mutex_lock(&workers[i].lock);
|
|
371
|
+
workers[i].compute_type = global_compute_type;
|
|
372
|
+
pthread_mutex_unlock(&workers[i].lock);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
pthread_mutex_unlock(&global_lock);
|
|
376
|
+
|
|
377
|
+
Py_RETURN_NONE;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Get computation type
|
|
381
|
+
static PyObject *get_computation_type(PyObject *self, PyObject *args) {
|
|
382
|
+
pthread_mutex_lock(&global_lock);
|
|
383
|
+
int comp_type = (int)global_compute_type;
|
|
384
|
+
pthread_mutex_unlock(&global_lock);
|
|
385
|
+
|
|
386
|
+
return PyLong_FromLong(comp_type);
|
|
387
|
+
}
|
|
388
|
+
|
|
220
389
|
// Shutdown all threads
|
|
221
390
|
static PyObject *shutdown_loader(PyObject *self, PyObject *args) {
|
|
222
391
|
pthread_mutex_lock(&global_lock);
|
|
@@ -246,6 +415,8 @@ static PyMethodDef CoreMethods[] = {
|
|
|
246
415
|
{"get_thread_load", get_thread_load, METH_VARARGS, "Get load for a thread"},
|
|
247
416
|
{"get_all_loads", get_all_loads, METH_NOARGS, "Get all thread loads"},
|
|
248
417
|
{"get_num_threads", get_num_threads, METH_NOARGS, "Get number of threads"},
|
|
418
|
+
{"set_computation_type", set_computation_type, METH_VARARGS, "Set computation type"},
|
|
419
|
+
{"get_computation_type", get_computation_type, METH_NOARGS, "Get computation type"},
|
|
249
420
|
{"shutdown", shutdown_loader, METH_NOARGS, "Shutdown the CPU loader"},
|
|
250
421
|
{NULL, NULL, 0, NULL}
|
|
251
422
|
};
|
|
@@ -57,6 +57,17 @@ class CPUMetricsResponse(BaseModel):
|
|
|
57
57
|
cpu_temperature: Optional[float] = None
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
class ComputationTypeRequest(BaseModel):
|
|
61
|
+
computation_type: str = Field(
|
|
62
|
+
..., description="Computation type: busy-wait, pi, primes, matrix, fibonacci"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ComputationTypeResponse(BaseModel):
|
|
67
|
+
computation_type: str
|
|
68
|
+
available_types: List[str]
|
|
69
|
+
|
|
70
|
+
|
|
60
71
|
# Global CPU loader instance, MQTT publisher, and WebSocket connections
|
|
61
72
|
cpu_loader = None
|
|
62
73
|
mqtt_publisher: Optional[MQTTPublisher] = None
|
|
@@ -150,6 +161,11 @@ async def lifespan(app: FastAPI):
|
|
|
150
161
|
# Startup
|
|
151
162
|
cpu_loader = CPULoader()
|
|
152
163
|
|
|
164
|
+
# Set computation type if specified in app state
|
|
165
|
+
computation_type = getattr(app.state, "computation_type", None)
|
|
166
|
+
if computation_type:
|
|
167
|
+
cpu_loader.set_computation_type_from_string(computation_type)
|
|
168
|
+
|
|
153
169
|
# Initialize MQTT publisher with settings from arguments or environment
|
|
154
170
|
mqtt_args = getattr(app.state, "mqtt_args", {})
|
|
155
171
|
try:
|
|
@@ -309,6 +325,30 @@ async def set_all_thread_loads(request: AllThreadsLoadRequest):
|
|
|
309
325
|
raise HTTPException(status_code=400, detail=str(e))
|
|
310
326
|
|
|
311
327
|
|
|
328
|
+
@app.get("/api/computation-type", response_model=ComputationTypeResponse)
|
|
329
|
+
async def get_computation_type():
|
|
330
|
+
"""Get the current computation type."""
|
|
331
|
+
current_type = cpu_loader.get_computation_type_string()
|
|
332
|
+
available_types = ["busy-wait", "pi", "primes", "matrix", "fibonacci"]
|
|
333
|
+
return ComputationTypeResponse(
|
|
334
|
+
computation_type=current_type, available_types=available_types
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
@app.put("/api/computation-type")
|
|
339
|
+
async def set_computation_type(request: ComputationTypeRequest):
|
|
340
|
+
"""Set the computation type for CPU load generation."""
|
|
341
|
+
try:
|
|
342
|
+
cpu_loader.set_computation_type_from_string(request.computation_type)
|
|
343
|
+
return {
|
|
344
|
+
"status": "success",
|
|
345
|
+
"computation_type": request.computation_type,
|
|
346
|
+
"message": f"Computation type set to {request.computation_type}",
|
|
347
|
+
}
|
|
348
|
+
except ValueError as e:
|
|
349
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
350
|
+
|
|
351
|
+
|
|
312
352
|
def parse_args():
|
|
313
353
|
"""Parse command-line arguments."""
|
|
314
354
|
parser = argparse.ArgumentParser(
|
|
@@ -330,6 +370,12 @@ def parse_args():
|
|
|
330
370
|
action="store_true",
|
|
331
371
|
help="Disable CPU temperature monitoring (useful if temperature sensors are unavailable)",
|
|
332
372
|
)
|
|
373
|
+
parser.add_argument(
|
|
374
|
+
"--computation-type",
|
|
375
|
+
choices=["busy-wait", "pi", "primes", "matrix", "fibonacci"],
|
|
376
|
+
default="busy-wait",
|
|
377
|
+
help="Type of computation to perform during CPU load generation (default: busy-wait)",
|
|
378
|
+
)
|
|
333
379
|
|
|
334
380
|
# MQTT arguments
|
|
335
381
|
mqtt_group = parser.add_argument_group("MQTT settings")
|
|
@@ -385,8 +431,9 @@ def run():
|
|
|
385
431
|
if args.mqtt_client_id:
|
|
386
432
|
mqtt_args["client_id"] = args.mqtt_client_id
|
|
387
433
|
|
|
388
|
-
# Store MQTT args in app state for lifespan to access
|
|
434
|
+
# Store MQTT args and computation type in app state for lifespan to access
|
|
389
435
|
app.state.mqtt_args = mqtt_args
|
|
436
|
+
app.state.computation_type = args.computation_type
|
|
390
437
|
|
|
391
438
|
# Run the server
|
|
392
439
|
uvicorn.run(app, host=args.host, port=args.port)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cpu-loader
|
|
3
|
-
Version: 0.4
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A tool to generate CPU load on a system with runtime configuration through a WebUI and REST API
|
|
5
5
|
Author-email: the78mole <the78mole@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: fastapi==0.122.0
|
|
29
29
|
Requires-Dist: uvicorn[standard]==0.38.0
|
|
30
|
-
Requires-Dist: pydantic==2.12.
|
|
30
|
+
Requires-Dist: pydantic==2.12.5
|
|
31
31
|
Requires-Dist: requests==2.32.5
|
|
32
32
|
Requires-Dist: psutil>=5.9.0
|
|
33
33
|
Requires-Dist: websockets>=12.0
|
|
@@ -47,11 +47,14 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
47
47
|
|
|
48
48
|
- **🎯 Precise Per-Thread Control**: Set individual CPU load (0-100%) for each core independently
|
|
49
49
|
- **⚡ High Performance**: Native C implementation with pthreads ensures accurate load generation
|
|
50
|
-
-
|
|
50
|
+
- **🧮 Configurable Algorithms**: Choose between 5 different computation types (busy-wait, PI, primes, matrix, fibonacci)
|
|
51
|
+
- **⏱️ Time-Controlled Execution**: All algorithms respect precise timing for accurate load percentages
|
|
52
|
+
- **📊 Real-Time Monitoring**: Live WebSocket updates showing actual CPU usage and temperature via `psutil`
|
|
51
53
|
- **🎛️ Interactive WebUI**: Beautiful gradient interface with sliders and visual feedback
|
|
52
54
|
- **🚀 REST API**: Complete programmatic control for automation and testing
|
|
53
55
|
- **📱 Responsive Design**: Works seamlessly on desktop and mobile devices
|
|
54
56
|
- **🔄 Instant Updates**: Changes take effect immediately with sub-second response time
|
|
57
|
+
- **🌡️ Temperature Monitoring**: Optional CPU temperature tracking with sensor auto-detection
|
|
55
58
|
- 📡 **MQTT Integration**: Publish metrics and settings to MQTT broker for IoT/monitoring systems
|
|
56
59
|
|
|
57
60
|
## 🖼️ Screenshots
|
|
@@ -59,23 +62,23 @@ A tool to generate CPU load on a system with runtime configuration through a Web
|
|
|
59
62
|
### Interface Screenshots
|
|
60
63
|
<table>
|
|
61
64
|
<tr>
|
|
62
|
-
<td width="
|
|
65
|
+
<td width="40%">
|
|
63
66
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/01-initial-view.png" alt="Initial view with zero load">
|
|
64
67
|
<p align="center"><em>Clean interface showing all CPU threads at idle</em></p>
|
|
65
68
|
</td>
|
|
66
|
-
<td width="
|
|
69
|
+
<td width="60%" rowspan="3" valign="top">
|
|
67
70
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/04-mobile-view.png" alt="Mobile responsive view">
|
|
68
71
|
<p align="center"><em>Fully responsive mobile interface</em></p>
|
|
69
72
|
</td>
|
|
70
73
|
</tr>
|
|
71
74
|
<tr>
|
|
72
|
-
<td width="
|
|
75
|
+
<td width="40%">
|
|
73
76
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/02-with-load.png" alt="Mixed load across threads">
|
|
74
77
|
<p align="center"><em>Different load levels: 50%, 75%, and 25% on individual threads</em></p>
|
|
75
78
|
</td>
|
|
76
79
|
</tr>
|
|
77
80
|
<tr>
|
|
78
|
-
<td width="
|
|
81
|
+
<td width="40%">
|
|
79
82
|
<img src="https://raw.githubusercontent.com/the78mole/cpu-loader/main/screenshots/03-live-metrics.png" alt="Live CPU metrics updating">
|
|
80
83
|
<p align="center"><em>Real-time metrics showing actual CPU usage with color-coded bars</em></p>
|
|
81
84
|
</td>
|
|
@@ -144,6 +147,8 @@ uv run src/main.py --help
|
|
|
144
147
|
**Available Options:**
|
|
145
148
|
- `--host HOST`: Host to bind the server to (default: 0.0.0.0)
|
|
146
149
|
- `--port PORT`: Port to bind the server to (default: 8000)
|
|
150
|
+
- `--disable-temperature`: Disable CPU temperature monitoring
|
|
151
|
+
- `--computation-type TYPE`: Set computation algorithm (busy-wait, pi, primes, matrix, fibonacci)
|
|
147
152
|
- `--mqtt-broker-host HOST`: MQTT broker hostname
|
|
148
153
|
- `--mqtt-broker-port PORT`: MQTT broker port (default: 1883)
|
|
149
154
|
- `--mqtt-username USER`: MQTT username
|
|
@@ -151,6 +156,30 @@ uv run src/main.py --help
|
|
|
151
156
|
- `--mqtt-topic-prefix PREFIX`: MQTT topic prefix (default: cpu-loader)
|
|
152
157
|
- `--mqtt-client-id ID`: MQTT client ID (default: cpu-loader)
|
|
153
158
|
|
|
159
|
+
#### Computation Types
|
|
160
|
+
|
|
161
|
+
CPU Loader supports different computation algorithms for load generation with **precise time control**:
|
|
162
|
+
|
|
163
|
+
- **`busy-wait`** (default): Simple busy loop - fastest execution, minimal overhead, most accurate timing
|
|
164
|
+
- **`pi`**: PI calculation using Leibniz formula - moderate computational intensity, mathematical workload
|
|
165
|
+
- **`primes`**: Prime number finding - variable computational load, cryptographic-style operations
|
|
166
|
+
- **`matrix`**: 4x4 matrix multiplication - consistent computational patterns, linear algebra operations
|
|
167
|
+
- **`fibonacci`**: Lightweight mathematical operations - balanced computational load with micro-pauses
|
|
168
|
+
|
|
169
|
+
All algorithms are **time-controlled** to ensure accurate load percentages. The system uses 10ms cycles with frequent timing checks to maintain precise CPU utilization.
|
|
170
|
+
|
|
171
|
+
**Examples:**
|
|
172
|
+
```bash
|
|
173
|
+
# Use PI calculation for CPU load
|
|
174
|
+
uv run cpu-loader --computation-type pi
|
|
175
|
+
|
|
176
|
+
# Use prime number calculation
|
|
177
|
+
uv run cpu-loader --computation-type primes --port 8001
|
|
178
|
+
|
|
179
|
+
# Use matrix multiplication
|
|
180
|
+
uv run cpu-loader --computation-type matrix
|
|
181
|
+
```
|
|
182
|
+
|
|
154
183
|
### WebUI
|
|
155
184
|
|
|
156
185
|
Open your browser and navigate to `http://localhost:8000`
|
|
@@ -202,6 +231,26 @@ curl -X POST http://localhost:8000/api/threads \
|
|
|
202
231
|
-d '{"num_threads": 8}'
|
|
203
232
|
```
|
|
204
233
|
|
|
234
|
+
#### Get Computation Type
|
|
235
|
+
```bash
|
|
236
|
+
curl http://localhost:8000/api/computation-type
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Response:
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"computation_type": "pi",
|
|
243
|
+
"available_types": ["busy-wait", "pi", "primes", "matrix", "fibonacci"]
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Set Computation Type
|
|
248
|
+
```bash
|
|
249
|
+
curl -X PUT http://localhost:8000/api/computation-type \
|
|
250
|
+
-H "Content-Type: application/json" \
|
|
251
|
+
-d '{"computation_type": "fibonacci"}'
|
|
252
|
+
```
|
|
253
|
+
|
|
205
254
|
## API Documentation
|
|
206
255
|
|
|
207
256
|
Once the server is running, visit `http://localhost:8000/docs` for interactive API documentation powered by Swagger UI.
|
|
@@ -307,6 +356,31 @@ The example demonstrates:
|
|
|
307
356
|
- Individual thread control
|
|
308
357
|
- Resetting to idle
|
|
309
358
|
|
|
359
|
+
### Computation Types Demo
|
|
360
|
+
|
|
361
|
+
A comprehensive demo script is available in `examples/computation_types_demo.py` to test all computation algorithms:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
# Start the server
|
|
365
|
+
uv run cpu-loader
|
|
366
|
+
|
|
367
|
+
# In another terminal, run the demo (tests all computation types)
|
|
368
|
+
python examples/computation_types_demo.py
|
|
369
|
+
|
|
370
|
+
# Test specific computation types only
|
|
371
|
+
python examples/computation_types_demo.py --types pi fibonacci
|
|
372
|
+
|
|
373
|
+
# Custom load and duration
|
|
374
|
+
python examples/computation_types_demo.py --load 50 --duration 15
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
The demo script:
|
|
378
|
+
|
|
379
|
+
- Tests each computation type systematically
|
|
380
|
+
- Monitors actual CPU usage vs. target load
|
|
381
|
+
- Provides performance comparisons between algorithms
|
|
382
|
+
- Shows timing accuracy for each computation method
|
|
383
|
+
|
|
310
384
|
## Architecture
|
|
311
385
|
|
|
312
386
|
- **src/cpu_loader_core.c**: High-performance C implementation using pthreads for CPU load generation
|
|
@@ -327,13 +401,22 @@ The example demonstrates:
|
|
|
327
401
|
|
|
328
402
|
## Use Cases
|
|
329
403
|
|
|
330
|
-
- **Performance Testing**: Test application behavior under various CPU loads
|
|
331
|
-
- **Stress Testing**: Validate system stability under high CPU utilization
|
|
332
|
-
- **Thermal Testing**:
|
|
333
|
-
- **Power Consumption Analysis**:
|
|
334
|
-
- **Benchmarking**: Create reproducible load scenarios
|
|
404
|
+
- **Performance Testing**: Test application behavior under various CPU loads and computation types
|
|
405
|
+
- **Stress Testing**: Validate system stability under high CPU utilization with different algorithms
|
|
406
|
+
- **Thermal Testing**: Use fibonacci or matrix computations for maximum heat generation
|
|
407
|
+
- **Power Consumption Analysis**: Compare power usage across different computation algorithms
|
|
408
|
+
- **Benchmarking**: Create reproducible load scenarios with specific computation patterns
|
|
409
|
+
- **Algorithm Testing**: Test cache performance (matrix), mathematical units (pi), or crypto operations (primes)
|
|
335
410
|
- **IoT Integration**: Integrate with Home Assistant, Node-RED, or other MQTT-based systems
|
|
336
|
-
- **Monitoring**: Feed CPU metrics into monitoring dashboards via MQTT
|
|
411
|
+
- **Monitoring**: Feed CPU metrics and temperature data into monitoring dashboards via MQTT
|
|
412
|
+
|
|
413
|
+
### Computation Algorithm Use Cases
|
|
414
|
+
|
|
415
|
+
- **`busy-wait`**: Baseline testing, pure timing validation, minimal computational overhead
|
|
416
|
+
- **`pi`**: Mathematical processing benchmarks, floating-point unit testing
|
|
417
|
+
- **`primes`**: Cryptographic algorithm simulation, integer arithmetic testing
|
|
418
|
+
- **`matrix`**: Linear algebra workloads, cache hierarchy testing, SIMD instruction testing
|
|
419
|
+
- **`fibonacci`**: Balanced computational load for general stress testing
|
|
337
420
|
|
|
338
421
|
## Development
|
|
339
422
|
|
|
@@ -363,10 +446,13 @@ Versions are automatically determined based on commit messages:
|
|
|
363
446
|
|
|
364
447
|
- **Patch bump** (0.0.X): Every commit to main
|
|
365
448
|
- **Minor bump** (0.X.0): Commits prefixed with `feat:`
|
|
449
|
+
|
|
366
450
|
```bash
|
|
367
451
|
git commit -m "feat: add new CPU monitoring feature"
|
|
368
452
|
```
|
|
453
|
+
|
|
369
454
|
- **Major bump** (X.0.0): Commits with `major:`, `breaking:`, or `BREAKING CHANGE:`
|
|
455
|
+
|
|
370
456
|
```bash
|
|
371
457
|
git commit -m "major: redesign API interface"
|
|
372
458
|
git commit -m "breaking: remove deprecated endpoints"
|
|
@@ -375,6 +461,7 @@ Versions are automatically determined based on commit messages:
|
|
|
375
461
|
#### Release Process
|
|
376
462
|
|
|
377
463
|
1. **Commit and push to main**:
|
|
464
|
+
|
|
378
465
|
```bash
|
|
379
466
|
git add .
|
|
380
467
|
git commit -m "feat: add WebSocket support"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|