@@ -97,45 +97,45 @@ dotnet-counters monitor -n DiagnosticScenarios
97
97
Press p to pause, r to resume, q to quit.
98
98
Status: Running
99
99
100
- Name Current Value
100
+ Name Current Value
101
101
[System.Runtime]
102
- dotnet.assembly.count ({assembly}) 115
102
+ dotnet.assembly.count ({assembly}) 115
103
103
dotnet.gc.collections ({collection})
104
104
gc.heap.generation
105
- gen0 2
106
- gen1 1
107
- gen2 1
108
- dotnet.gc.heap.total_allocated (By) 64,329,632
105
+ gen0 2
106
+ gen1 1
107
+ gen2 1
108
+ dotnet.gc.heap.total_allocated (By) 64,329,632
109
109
dotnet.gc.last_collection.heap.fragmentation.size (By)
110
110
gc.heap.generation
111
- gen0 199,920
112
- gen1 29,208
113
- gen2 0
114
- loh 32
115
- poh 0
111
+ gen0 199,920
112
+ gen1 29,208
113
+ gen2 0
114
+ loh 32
115
+ poh 0
116
116
dotnet.gc.last_collection.heap.size (By)
117
117
gc.heap.generation
118
- gen0 208,712
119
- gen1 3,456,000
120
- gen2 5,065,600
121
- loh 98,384
122
- poh 3,147,488
123
- dotnet.gc.last_collection.memory.committed_size (By) 31,096,832
124
- dotnet.gc.pause.time (s) 0.024
125
- dotnet.jit.compilation.time (s) 1.285
126
- dotnet.jit.compiled_il.size (By) 565,249
127
- dotnet.jit.compiled_methods ({method}) 5,831
128
- dotnet.monitor.lock_contentions ({contention}) 148
129
- dotnet.process.cpu.count ({cpu}) 16
118
+ gen0 208,712
119
+ gen1 3,456,000
120
+ gen2 5,065,600
121
+ loh 98,384
122
+ poh 3,147,488
123
+ dotnet.gc.last_collection.memory.committed_size (By) 31,096,832
124
+ dotnet.gc.pause.time (s) 0.024
125
+ dotnet.jit.compilation.time (s) 1.285
126
+ dotnet.jit.compiled_il.size (By) 565,249
127
+ dotnet.jit.compiled_methods ({method}) 5,831
128
+ dotnet.monitor.lock_contentions ({contention}) 148
129
+ dotnet.process.cpu.count ({cpu}) 16
130
130
dotnet.process.cpu.time (s)
131
131
cpu.mode
132
- system 2.156
133
- user 2.734
134
- dotnet.process.memory.working_set (By) 1.3217e+08
135
- dotnet.thread_pool.queue.length ({work_item}) 0
136
- dotnet.thread_pool.thread.count ({thread}) 0
137
- dotnet.thread_pool.work_item.count ({work_item}) 32,267
138
- dotnet.timer.count ({timer}) 0
132
+ system 2.156
133
+ user 2.734
134
+ dotnet.process.memory.working_set (By) 1.3217e+08
135
+ dotnet.thread_pool.queue.length ({work_item}) 0
136
+ dotnet.thread_pool.thread.count ({thread}) 0
137
+ dotnet.thread_pool.work_item.count ({work_item}) 32,267
138
+ dotnet.timer.count ({timer}) 0
139
139
```
140
140
141
141
The counters above are an example while the web server wasn't serving any requests. Run Bombardier again with the ` api/diagscenario/tasksleepwait ` endpoint and sustained load for 2 minutes so there's plenty of time to observe what happens to the performance counters.
@@ -148,43 +148,43 @@ ThreadPool starvation occurs when there are no free threads to handle the queued
148
148
149
149
``` dotnetcli
150
150
[System.Runtime]
151
- dotnet.assembly.count ({assembly}) 115
151
+ dotnet.assembly.count ({assembly}) 115
152
152
dotnet.gc.collections ({collection})
153
153
gc.heap.generation
154
- gen0 5
155
- gen1 1
156
- gen2 1
157
- dotnet.gc.heap.total_allocated (By) 1.6947e+08
154
+ gen0 5
155
+ gen1 1
156
+ gen2 1
157
+ dotnet.gc.heap.total_allocated (By) 1.6947e+08
158
158
dotnet.gc.last_collection.heap.fragmentation.size (By)
159
159
gc.heap.generation
160
- gen0 0
161
- gen1 348,248
162
- gen2 0
163
- loh 32
164
- poh 0
160
+ gen0 0
161
+ gen1 348,248
162
+ gen2 0
163
+ loh 32
164
+ poh 0
165
165
dotnet.gc.last_collection.heap.size (By)
166
166
gc.heap.generation
167
- gen0 0
168
- gen1 18,010,920
169
- gen2 5,065,600
170
- loh 98,384
171
- poh 3,407,048
172
- dotnet.gc.last_collection.memory.committed_size (By) 66,842,624
173
- dotnet.gc.pause.time (s) 0.05
174
- dotnet.jit.compilation.time (s) 1.317
175
- dotnet.jit.compiled_il.size (By) 574,886
176
- dotnet.jit.compiled_methods ({method}) 6,008
177
- dotnet.monitor.lock_contentions ({contention}) 194
178
- dotnet.process.cpu.count ({cpu}) 16
167
+ gen0 0
168
+ gen1 18,010,920
169
+ gen2 5,065,600
170
+ loh 98,384
171
+ poh 3,407,048
172
+ dotnet.gc.last_collection.memory.committed_size (By) 66,842,624
173
+ dotnet.gc.pause.time (s) 0.05
174
+ dotnet.jit.compilation.time (s) 1.317
175
+ dotnet.jit.compiled_il.size (By) 574,886
176
+ dotnet.jit.compiled_methods ({method}) 6,008
177
+ dotnet.monitor.lock_contentions ({contention}) 194
178
+ dotnet.process.cpu.count ({cpu}) 16
179
179
dotnet.process.cpu.time (s)
180
180
cpu.mode
181
- system 4.953
182
- user 6.266
183
- dotnet.process.memory.working_set (By) 1.3217e+08
184
- dotnet.thread_pool.queue.length ({work_item}) 0
185
- dotnet.thread_pool.thread.count ({thread}) 133
186
- dotnet.thread_pool.work_item.count ({work_item}) 71,188
187
- dotnet.timer.count ({timer}) 124
181
+ system 4.953
182
+ user 6.266
183
+ dotnet.process.memory.working_set (By) 1.3217e+08
184
+ dotnet.thread_pool.queue.length ({work_item}) 0
185
+ dotnet.thread_pool.thread.count ({thread}) 133
186
+ dotnet.thread_pool.work_item.count ({work_item}) 71,188
187
+ dotnet.timer.count ({timer}) 124
188
188
```
189
189
190
190
Once the count of ThreadPool threads stabilizes, the pool is no longer starving. But if it stabilizes at a high value (more than about three times the number of processor cores), that usually indicates the application code is blocking some ThreadPool threads and the ThreadPool is compensating by running with more threads. Running steady at high thread counts won't necessarily have large impacts on request latency, but if load varies dramatically over time or the app will be periodically restarted, then each time the ThreadPool is likely to enter a period of starvation where it's slowly increasing threads and delivering poor request latency. Each thread also consumes memory, so reducing the total number of threads needed provides another benefit.
0 commit comments