|
| 1 | +.. include:: ../disclaimer-sp.rst |
| 2 | + |
| 3 | +:Original: :ref:`Documentation/scheduler/sched-design-CFS.rst <sched_design_CFS>` |
| 4 | +:Translator: Sergio González Collado < [email protected]> |
| 5 | + |
| 6 | +.. _sp_sched_bwc: |
| 7 | + |
| 8 | +================================= |
| 9 | +CFS con control de ancho de banda |
| 10 | +================================= |
| 11 | + |
| 12 | +.. note:: |
| 13 | + Este documento únicamente trata el control de ancho de banda de CPUs |
| 14 | + para SCHED_NORMAL. El caso de SCHED_RT se trata en Documentation/scheduler/sched-rt-group.rst |
| 15 | + |
| 16 | +El control de ancho de banda es una extensión CONFIG_FAIR_GROUP_SCHED que |
| 17 | +permite especificar el máximo uso disponible de CPU para un grupo o una jerarquía. |
| 18 | + |
| 19 | +El ancho de banda permitido para un grupo de tareas se especifica usando una |
| 20 | +cuota y un periodo. Dentro de un "periodo" (microsegundos), a un grupo |
| 21 | +de tareas se le asigna hasta su "cuota" de tiempo de uso de CPU en |
| 22 | +microsegundos. Esa cuota es asignada para cada CPU en colas de ejecución |
| 23 | +en porciones de tiempo de ejecución en la CPU según los hilos de ejecución |
| 24 | +del grupo de tareas van siendo candidatos a ejecutarse. Una vez toda la cuota |
| 25 | +ha sido asignada cualquier petición adicional de cuota resultará en esos hilos |
| 26 | +de ejecución siendo limitados/estrangulados. Los hilos de ejecución limitados |
| 27 | +no serán capaces de ejecutarse de nuevo hasta el siguiente periodo cuando |
| 28 | +la cuota sea restablecida. |
| 29 | + |
| 30 | +La cuota sin asignar de un grupo es monitorizada globalmente, siendo |
| 31 | +restablecidas cfs_quota unidades al final de cada periodo. Según los |
| 32 | +hilos de ejecución van consumiendo este ancho de banda, este se |
| 33 | +transfiere a los "silos" de las cpu-locales en base a la demanda. La |
| 34 | +cantidad transferida en cada una de esas actualizaciones es ajustable y |
| 35 | +es descrito como un "slice". |
| 36 | + |
| 37 | +Característica de ráfaga |
| 38 | +-------------------------- |
| 39 | + |
| 40 | +Esta característica toma prestado tiempo ahora, que en un futuro tendrá que |
| 41 | +devolver, con el coste de una mayor interferencia hacia los otros usuarios |
| 42 | +del sistema. Todo acotado perfectamente. |
| 43 | + |
| 44 | +El tradicional control de ancho de banda (UP-EDF) es algo como: |
| 45 | + |
| 46 | + (U = \Sum u_i) <= 1 |
| 47 | + |
| 48 | +Esto garantiza dos cosas: que cada tiempo límite de ejecución es cumplido |
| 49 | +y que el sistema es estable. De todas formas, si U fuese > 1, entonces |
| 50 | +por cada segundo de tiempo de reloj de una tarea, tendríamos que |
| 51 | +ejecutar más de un segundo y obviamente no se cumpliría con el tiempo |
| 52 | +límite de ejecución de la tarea, pero en el siguiente periodo de ejecución |
| 53 | +el tiempo límite de la tarea estaría todavía más lejos, y nunca se tendría |
| 54 | +tiempo de alcanzar la ejecución, cayendo así en un fallo no acotado. |
| 55 | + |
| 56 | +La característica de ráfaga implica que el trabajo de una tarea no siempre |
| 57 | +consuma totalmente la cuota; esto permite que se pueda describir u_i |
| 58 | +como una distribución estadística. |
| 59 | + |
| 60 | +Por ejemplo, se tiene u_i = {x,e}_i, donde x es el p(95) y x+e p(100) |
| 61 | +(el tradicional WCET (WCET:Worst Case Execution Time: son las siglas |
| 62 | +en inglés para "peor tiempo de ejecución")). Esto efectivamente permite |
| 63 | +a u ser más pequeño, aumentando la eficiencia (podemos ejecutar más |
| 64 | +tareas en el sistema), pero al coste de perder el instante límite de |
| 65 | +finalización deseado de la tarea, cuando coincidan las peores |
| 66 | +probabilidades. De todas formas, si se mantiene la estabilidad, ya que |
| 67 | +cada sobre-ejecución se empareja con una infra-ejecución en tanto x esté |
| 68 | +por encima de la media. |
| 69 | + |
| 70 | +Es decir, supóngase que se tienen 2 tareas, ambas específicamente |
| 71 | +con p(95), entonces tenemos p(95)*p(95) = 90.25% de probabilidad de |
| 72 | +que ambas tareas se ejecuten dentro de su cuota asignada y todo |
| 73 | +salga bien. Al mismo tiempo se tiene que p(5)*p(5) = 0.25% de |
| 74 | +probabilidad que ambas tareas excedan su cuota de ejecución (fallo |
| 75 | +garantizado de su tiempo final de ejecución). En algún punto por |
| 76 | +en medio, hay un umbral donde una tarea excede su tiempo límite de |
| 77 | +ejecución y la otra no, de forma que se compensan; esto depende de la |
| 78 | +función de probabilidad acumulada específica de la tarea. |
| 79 | + |
| 80 | +Al mismo tiempo, se puede decir que el peor caso de sobrepasar el |
| 81 | +tiempo límite de ejecución será \Sum e_i; esto es una retraso acotado |
| 82 | +(asumiendo que x+e es de hecho el WCET). |
| 83 | + |
| 84 | +La interferencia cuando se usa una ráfaga se evalúa por las posibilidades |
| 85 | +de fallar en el cumplimiento del tiempo límite y el promedio de WCET. |
| 86 | +Los resultados de los tests han mostrado que cuando hay muchos cgroups o |
| 87 | +una CPU está infrautilizada, la interferencia es más limitada. Más detalles |
| 88 | +se aportan en: https://lore.kernel.org/lkml/ [email protected]/ |
| 89 | + |
| 90 | +Gestión: |
| 91 | +-------- |
| 92 | + |
| 93 | +Cuota, periodo y ráfaga se gestionan dentro del subsistema de cpu por medio |
| 94 | +de cgroupfs. |
| 95 | + |
| 96 | +.. note:: |
| 97 | + Los archivos cgroupfs descritos en esta sección solo se aplican al cgroup |
| 98 | + v1. Para cgroup v2, ver :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`. |
| 99 | + |
| 100 | +- cpu.cfs_quota_us: tiempo de ejecución que se refresca cada periodo (en microsegundos) |
| 101 | +- cpu.cfs_period_us: la duración del periodo (en microsegundos) |
| 102 | +- cpu.stat: exporta las estadísticas de limitación [explicado a continuación] |
| 103 | +- cpu.cfs_burst_us: el máximo tiempo de ejecución acumulado (en microsegundos) |
| 104 | + |
| 105 | +Los valores por defecto son:: |
| 106 | + |
| 107 | + cpu.cfs_period_us=100ms |
| 108 | + cpu.cfs_quota_us=-1 |
| 109 | + cpu.cfs_burst_us=0 |
| 110 | + |
| 111 | +Un valor de -1 para cpu.cfs_quota_us indica que el grupo no tiene ninguna |
| 112 | +restricción de ancho de banda aplicado, ese grupo se describe como un grupo |
| 113 | +con ancho de banda sin restringir. Esto representa el comportamiento |
| 114 | +tradicional para CFS. |
| 115 | + |
| 116 | +Asignar cualquier valor (válido) y positivo no menor que cpu.cfs_burst_us |
| 117 | +definirá el límite del ancho de banda. La cuota mínima permitida para |
| 118 | +la cuota o periodo es 1ms. Hay también un límite superior en la duración del |
| 119 | +periodo de 1s. Existen restricciones adicionales cuando los límites de |
| 120 | +ancho de banda se usan de manera jerárquica, estos se explican en mayor |
| 121 | +detalle más adelante. |
| 122 | + |
| 123 | +Asignar cualquier valor negativo a cpu.cfs_quota_us eliminará el límite de |
| 124 | +ancho de banda y devolverá de nuevo al grupo a un estado sin restricciones. |
| 125 | + |
| 126 | +Un valor de 0 para cpu.cfs_burst_us indica que el grupo no puede acumular |
| 127 | +ningún ancho de banda sin usar. Esto hace que el control del comportamiento |
| 128 | +tradicional del ancho de banda para CFS no cambie. Definir cualquier valor |
| 129 | +(válido) positivo no mayor que cpu.cfs_quota_us en cpu.cgs_burst_us definirá |
| 130 | +el límite con el ancho de banda acumulado no usado. |
| 131 | + |
| 132 | +Cualquier actualización a las especificaciones del ancho de banda usado |
| 133 | +por un grupo resultará en que se deje de limitar si está en un estado |
| 134 | +restringido. |
| 135 | + |
| 136 | +Ajustes globales del sistema |
| 137 | +---------------------------- |
| 138 | + |
| 139 | +Por eficiencia el tiempo de ejecución es transferido en lotes desde una reserva |
| 140 | +global y el "silo" de una CPU local. Esto reduce en gran medida la presión |
| 141 | +por la contabilidad en grandes sistemas. La cantidad transferida cada vez |
| 142 | +que se requiere una actualización se describe como "slice". |
| 143 | + |
| 144 | +Esto es ajustable vía procfs:: |
| 145 | + |
| 146 | + /proc/sys/kernel/sched_cfs_bandwidth_slice_us (valor por defecto=5ms) |
| 147 | + |
| 148 | +Valores de "slice" más grandes reducirán el costo de transferencia, mientras |
| 149 | +que valores más pequeños permitirán un control más fino del consumo. |
| 150 | + |
| 151 | +Estadísticas |
| 152 | +------------ |
| 153 | + |
| 154 | +Las estadísticas del ancho de banda de un grupo se exponen en 5 campos en cpu.stat. |
| 155 | + |
| 156 | +cpu.stat: |
| 157 | + |
| 158 | +- nr_periods: Número de intervalos aplicados que han pasado. |
| 159 | +- nr_throttled: Número de veces que el grupo ha sido restringido/limitado. |
| 160 | +- throttled_time: La duración de tiempo total (en nanosegundos) en las |
| 161 | + que las entidades del grupo han sido limitadas. |
| 162 | +- nr_bursts: Número de periodos en que ha ocurrido una ráfaga. |
| 163 | +- burst_time: Tiempo acumulado (en nanosegundos) en la que una CPU ha |
| 164 | + usado más de su cuota en los respectivos periodos. |
| 165 | + |
| 166 | +Este interfaz es de solo lectura. |
| 167 | + |
| 168 | +Consideraciones jerárquicas |
| 169 | +--------------------------- |
| 170 | + |
| 171 | +La interfaz refuerza que el ancho de banda de una entidad individual |
| 172 | +sea siempre factible, esto es: max(c_i) <= C. De todas maneras, |
| 173 | +la sobre-suscripción en el caso agregado está explícitamente permitida |
| 174 | +para hacer posible semánticas de conservación de trabajo dentro de una |
| 175 | +jerarquia. |
| 176 | + |
| 177 | + e.g. \Sum (c_i) puede superar C |
| 178 | + |
| 179 | +[ Donde C es el ancho de banda de el padre, y c_i el de su hijo ] |
| 180 | + |
| 181 | +Hay dos formas en las que un grupo puede ser limitado: |
| 182 | + |
| 183 | + a. este consume totalmente su propia cuota en un periodo. |
| 184 | + b. la cuota del padre es consumida totalmente en su periodo. |
| 185 | + |
| 186 | +En el caso b) anterior, incluso si el hijo pudiera tener tiempo de |
| 187 | +ejecución restante, este no le será permitido hasta que el tiempo de |
| 188 | +ejecución del padre sea actualizado. |
| 189 | + |
| 190 | +Advertencias sobre el CFS con control de cuota de ancho de banda |
| 191 | +---------------------------------------------------------------- |
| 192 | + |
| 193 | +Una vez una "slice" se asigna a una cpu esta no expira. A pesar de eso todas, |
| 194 | +excepto las "slices" menos las de 1ms, puede ser devueltas a la reserva global |
| 195 | +si todos los hilos en esa cpu pasan a ser no ejecutables. Esto se configura |
| 196 | +en el tiempo de compilación por la variable min_cfs_rq_runtime. Esto es un |
| 197 | +ajuste en la eficacia que ayuda a prevenir añadir bloqueos en el candado global. |
| 198 | + |
| 199 | +El hecho de que las "slices" de una cpu local no expiren tiene como resultado |
| 200 | +algunos casos extremos interesantes que debieran ser comprendidos. |
| 201 | + |
| 202 | +Para una aplicación que es un cgroup y que está limitada en su uso de cpu |
| 203 | +es un punto discutible ya que de forma natural consumirá toda su parte |
| 204 | +de cuota así como también la totalidad de su cuota en cpu locales en cada |
| 205 | +periodo. Como resultado se espera que nr_periods sea aproximadamente igual |
| 206 | +a nr_throttled, y que cpuacct.usage se incremente aproximadamente igual |
| 207 | +a cfs_quota_us en cada periodo. |
| 208 | + |
| 209 | +Para aplicaciones que tienen un gran número de hilos de ejecución y que no |
| 210 | +estan ligadas a una cpu, este matiz de la no-expiración permite que las |
| 211 | +aplicaciones brevemente sobrepasen su cuota límite en la cantidad que |
| 212 | +no ha sido usada en cada cpu en la que el grupo de tareas se está ejecutando |
| 213 | +(típicamente como mucho 1ms por cada cpu o lo que se ha definido como |
| 214 | +min_cfs_rq_runtime). Este pequeño sobreuso únicamente tiene lugar si |
| 215 | +la cuota que ha sido asignada a una cpu y no ha sido completamente usada |
| 216 | +o devuelta en periodos anteriores. Esta cantidad de sobreuso no será |
| 217 | +transferida entre núcleos. Como resultado, este mecanismo todavía cumplirá |
| 218 | +estrictamente los límites de la tarea de grupo en el promedio del uso, |
| 219 | +pero sobre una ventana de tiempo mayor que un único periodo. Esto |
| 220 | +también limita la habilidad de un sobreuso a no más de 1ms por cada cpu. |
| 221 | +Esto provee de una experiencia de uso más predecible para aplicaciones |
| 222 | +con muchos hilos y con límites de cuota pequeños en máquinas con muchos |
| 223 | +núcleos. Esto también elimina la propensión a limitar estas |
| 224 | +aplicaciones mientras que simultáneamente usan menores cuotas |
| 225 | +de uso por cpu. Otra forma de decir esto es que permitiendo que |
| 226 | +la parte no usada de una "slice" permanezca válida entre periodos |
| 227 | +disminuye la posibilidad de malgastare cuota que va a expirar en |
| 228 | +las reservas de la cpu locales que no necesitan una "slice" completa |
| 229 | +de tiempo de ejecución de cpu. |
| 230 | + |
| 231 | +La interacción entre las aplicaciones ligadas a una CPU y las que no están |
| 232 | +ligadas a ninguna cpu ha de ser también considerada, especialmente cuando |
| 233 | +un único núcleo tiene un uso del 100%. Si se da a cada una de esas |
| 234 | +aplicaciones la mitad de la capacidad de una CPU-núcleo y ambas |
| 235 | +están gestionadas en la misma CPU es teóricamente posible que la aplicación |
| 236 | +no ligada a ninguna CPU use su 1ms adicional de cuota en algunos periodos, |
| 237 | +y por tanto evite que la aplicación ligada a una CPU pueda usar su |
| 238 | +cuota completa por esa misma cantidad. En esos caso el algoritmo CFS (vea |
| 239 | +sched-design-CFS.rst) el que decida qué aplicación es la elegida para |
| 240 | +ejecutarse, ya que ambas serán candidatas a ser ejecutadas y tienen |
| 241 | +cuota restante. Esta discrepancia en el tiempo de ejecución se compensará |
| 242 | +en los periodos siguientes cuando el sistema esté inactivo. |
| 243 | + |
| 244 | +Ejemplos |
| 245 | +--------- |
| 246 | + |
| 247 | +1. Un grupo limitado a 1 CPU de tiempo de ejecución. |
| 248 | + |
| 249 | + Si el periodo son 250ms y la cuota son 250ms el grupo de tareas tendrá el tiempo |
| 250 | + de ejecución de 1 CPU cada 250ms:: |
| 251 | + |
| 252 | + # echo 250000 > cpu.cfs_quota_us /* cuota = 250ms */ |
| 253 | + # echo 250000 > cpu.cfs_period_us /* periodo = 250ms */ |
| 254 | +
|
| 255 | +2. Un grupo limitado al tiempo de ejecución de 2 CPUs en una máquina varias CPUs. |
| 256 | + |
| 257 | + Con un periodo de 500ms y una cuota de 1000ms el grupo de tareas tiene el tiempo |
| 258 | + de ejecución de 2 CPUs cada 500ms:: |
| 259 | + |
| 260 | + # echo 1000000 > cpu.cfs_quota_us /* cuota = 1000ms */ |
| 261 | + # echo 500000 > cpu.cfs_period_us /* periodo = 500ms */ |
| 262 | +
|
| 263 | + El periodo más largo aquí permite una capacidad de ráfaga mayor. |
| 264 | + |
| 265 | +3. Un grupo limitado a un 20% de 1 CPU. |
| 266 | + |
| 267 | + Con un periodo de 50ms, 10ms de cuota son equivalentes al 20% de 1 CPUs:: |
| 268 | + |
| 269 | + # echo 10000 > cpu.cfs_quota_us /* cuota = 10ms */ |
| 270 | + # echo 50000 > cpu.cfs_period_us /* periodo = 50ms */ |
| 271 | +
|
| 272 | + Usando un periodo pequeño aquí nos aseguramos una respuesta de |
| 273 | + la latencia consistente a expensas de capacidad de ráfaga. |
| 274 | + |
| 275 | +4. Un grupo limitado al 40% de 1 CPU, y permite acumular adicionalmente |
| 276 | + hasta un 20% de 1 CPU. |
| 277 | + |
| 278 | + Con un periodo de 50ms, 20ms de cuota son equivalentes al 40% de |
| 279 | + 1 CPU. Y 10ms de ráfaga, son equivalentes a un 20% de 1 CPU:: |
| 280 | + |
| 281 | + # echo 20000 > cpu.cfs_quota_us /* cuota = 20ms */ |
| 282 | + # echo 50000 > cpu.cfs_period_us /* periodo = 50ms */ |
| 283 | + # echo 10000 > cpu.cfs_burst_us /* ráfaga = 10ms */ |
| 284 | +
|
| 285 | + Un ajuste mayor en la capacidad de almacenamiento (no mayor que la cuota) |
| 286 | + permite una mayor capacidad de ráfaga. |
| 287 | + |
0 commit comments