c linux linux-kernel load-balancing

c - Linux Kernel- task_h_load



linux kernel github (2)

El equilibrio de carga se invoca si se configura SMP. Linux utiliza el Programador completamente justo (CFS) para programar cada tarea de modo que cada uno obtenga una parte "justa" del tiempo del procesador. CFS usa el concepto de árbol rojo-negro .

El programador registra la hora actual cuando una tarea ingresa en la cola de ejecución. Mientras el proceso espera el tiempo del procesador, su valor de "espera" se incrementa en una cantidad derivada del número total de tareas actualmente en la cola de ejecución y la prioridad del proceso. Cuando el procesador ejecuta esta tarea, este valor de "espera" se decrementa. Si este valor cae por debajo de cierto valor, el programador se adelantará a la tarea y la otra tarea se acercará más al procesador para ejecutarse. CFS siempre trata de mantener la situación ideal manteniendo el valor de "espera" en cero.

Hay dos funciones en linux load_balance y select_task_rq_fair() que realizan la tarea de equilibrio de carga.

En palabras simples, el mecanismo de equilibrio de carga CFS descarga la CPU ocupada a una menos ocupada o ideal.

task_h_load se utiliza para calcular el peso de la tarea.

Lo que no entiendo es qué / cómo se calcula la carga en task_h_load. ¿Cómo se calcula en la función task_h_load?

Este factor de peso depende del buen valor del proceso.

weighting factor = weight of process with nice value 0 / weight of current task;

donde '' weight '' es aproximadamente equivalente a 1024 * (1.25) ^ (- bonito)

Por ejemplo: el peso es 820 para el valor agradable 1 el peso es 1277 para el valor agradable -1

task_h_load
Para obtener más información sobre los métodos y los aspectos básicos del equilibrio de carga, consulte el comentario del kernel. task_h_load usa update_cfs_rq_h_load para calcular la carga jerárquica de la cola de ejecución para una planificación de tiempo justa y utiliza load_avg .

El tiempo de ejecución virtual es el tiempo ponderado que una tarea ha ejecutado en la CPU. CFS siempre trata de mantener this árbol rojo-negro en equilibrio.

<- valor más pequeño ----------- valor vruntime -------- valor más grande ->

Cada tarea ejecutable se coloca en un árbol Negro Rojo de auto equilibrio basado en vruntime . Si la tarea está lista para ejecutarse (significa que la tarea no está esperando ningún recurso), se coloca en el árbol. Si la tarea está esperando algún recurso (es decir, esperando la E / S), se elimina. Las tareas que tienen menos tiempo de procesamiento (significa menor tiempo de vruntime ) son hacia el lado izquierdo del árbol y las tareas que tienen más tiempo de procesamiento son el lado derecho del árbol.

El nodo izquierdo tiene el valor clave más pequeño (para CFS, es la tarea con mayor prioridad). El árbol negro rojo de auto equilibrio necesita la operación O (lgN) para navegar hacia el nodo izquierdo. El programador almacena en caché este valor en rb_leftmost . Al recuperar solo este valor, el programador determina qué tarea ejecutar a continuación

Este equilibrio de carga se usa para tareas no reales, solo para tareas en tiempo real , se utilizan operaciones push-pull desarrolladas por Steven Rostedt y Gregory Haskins

Una cosa más acerca de CFS también es útil en la programación de grupos justos. Considere la figura a continuación

move_tasks es simplemente tratar de subir la carga ponderada por desequilibrio (significa después de calcular el factor de carga como se muestra arriba) de los this_rq a this_rq . Intenta igualar el equilibrio de carga de ambas colas de ejecución para que ambos puedan ahorrar tiempo de procesador "justo".

detach_task separa la tarea para la migración especificada en el puntero env del kernel de Linux.

detach_one_task intenta anular exactamente una tarea de env-> src_rq.

detach_tasks intenta separar hasta desequilibrar la carga ponderada de busiest_rq . Y devuelve el número de tareas separadas o, de lo contrario, cero si no se puede separar.

Para adjuntar esta tarea separada a la nueva rq (cola de ejecución), attach_task, attach_one_task,attach_tasks se usa de acuerdo con la situación.

La nueva comprobación de advertencia lockdep_assert_held() se introduce en detach_tasks que no estaba presente en move_tasks

En el multiprocesador, no es fácil mover la tarea tan fácilmente, por lo tanto, cfs realiza el equilibrio de carga específico del dominio como se muestra a continuación:

Para que todo esto se entienda, me gustaría que siguiera la siguiente referencia.

  1. Métrica de seguimiento de carga por entidad para equilibrio de carga

  2. factor de peso

  3. Open-suse

  4. Robert-love capitulo 3

  5. CPU-scheduling

Leí especialmente toda esta documentación para responder a su pregunta. Espero que no le importe comentar si falta algo.

Estoy tratando de entender qué sucede durante la función load_balance .
Estoy revisando la versión 3.14, pero también eché un vistazo a la versión 4.3 ya que me dijeron que el mecanismo fue cambiado y un poco más claro en esta versión.

en v3.14 la llamada es de move_tasks

en v4.3 la llamada es de detach_tasks

por lo que veo es la misma función pero solo con un nombre diferente.

Esta función es mover las tareas de una cola a otra de acuerdo con el parámetro env->balance .
Lo que no entiendo es qué / cómo se calcula la carga en task_h_load .

¿Alguien sabe qué representa el miembro de carga y cómo se calcula en la función task_h_load ?


CFS tiene un árbol de "entidades de programación". Cada entidad de programación puede tener su propio árbol, y así sucesivamente de forma recursiva ... (Esto es útil, por ejemplo, para agrupar todos los procesos de un usuario específico en una entidad de programación; por lo tanto, evita que un usuario que tiene muchas tareas consumiendo más tiempo de CPU que los usuarios con menos procesos)

task_h_load - significa " carga jerárquica de tareas "

Dado que una tarea se puede anidar en unos pocos árboles, el cálculo de su carga no es tan simple ...

static unsigned long task_h_load(struct task_struct *p){ struct cfs_rq *cfs_rq = task_cfbs_rq(p); update_cfs_rq_h_load(cfs_rq); return div64_ul(p->se.avg.load_avg * cfs_rq->h_load, cfs_rq_load_avg(cfs_rq) + 1); }

Al principio, cfs_rq apunta al árbol inmediato en el que se encuentra p. Si solo tuviéramos dos árboles anidados, calcular la carga de p hubiera sido sencillo:

task_h_load = task_load_in_its_tree * (load_of_immediate_tree / load_of_containing_tree);

(mientras que alert_tree se refiere al árbol que contiene la tarea, y using_tree se refiere al árbol que contiene el árbol que contiene la tarea).

Pero este no es el caso. Nuestro árbol podría ser un árbol anidado dentro de una entidad de programación, que en sí misma es solo una hoja en otro árbol.

Entonces, lo primero que hacemos es llamar a update_cfs_rq_h_load(cfs_rq) que calcula el factor de carga jerárquico para cfs_rq y todos sus ascendentes (ancestros): esta función sube la jerarquía del árbol hasta la raíz y desde la raíz hasta nuestro cfs_rq mientras cfs_rq el factor de carga jerárquico para cada árbol en la jerarquía.

El cálculo se realiza de manera similar:

cfs_rq_h_load = cfs_rq_load_in_its_tree * (load_of_immediate_tree / load_of_containing_tree)

Entonces, finalmente tenemos la carga fraccionaria de cfs_rq y todo lo que tenemos que hacer es calcular la h_load usando la misma fórmula.

task_h_load = task_load_in_its_tree * (load_of_immediate_tree / load_of_containing_tree)