Optimización del rendimiento de Linux (15) - Enlace de CPU

Una CPU aislada

1. Introducción a la CPU aislada

Para tareas con uso intensivo de CPU con alta carga de CPU, se recomienda configurar CPU Affinity para mejorar la eficiencia de ejecución de tareas, evitar el cambio de contexto de CPU y aumentar la tasa de aciertos de la caché de CPU.
De forma predeterminada, el programador del kernel de Linux puede usar cualquier núcleo de CPU. Si una tarea específica (proceso / subproceso) necesita monopolizar un núcleo de CPU y no desea que otras tareas (proceso / subproceso) lo usen, puede aislar la CPU especificada sin permitir que otras. Uso del proceso.

2. Las características de la CPU aislada

La CPU aislada puede mejorar eficazmente el rendimiento en tiempo real de las tareas que se ejecutan en la CPU aislada. Al tiempo que garantiza la ejecución de las tareas en la CPU aislada, reducirá los recursos de la CPU que pueden ejecutar otras tareas. Por lo tanto, es necesario planificar los recursos de la CPU de la computadora.

3. Aislar la configuración de la CPU

El parámetro de inicio isolcpus en el kernel de Linux se usa para aislar una o más CPU en el algoritmo de programación balanceada SMP, y el proceso especificado se coloca en una CPU aislada para ejecutarse a través de la configuración de CPU Affinity.
isolcpus= cpu_number [, cpu_number ,...]
(1) Modifique el archivo de configuración de grub. La
configuración de grub predeterminada es / etc / default / grub, e isolcpus = 11,12,13,14,15 se agrega al valor de GRUB_CMDLINE_LINUX. Todos los núcleos de CPU deben estar separados por comas y los rangos de área no son compatibles.
GRUB_CMDLINE_LINUX="isolcpus=1,2 crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet"
(2) Actualice grub
y vuelva a generar el archivo de inicio de grub /boot/grub/grub.cfg, y reinicie el sistema para que surta efecto.

update-grub
update-grub2
grub-mkconfig -o /boot/grub/grub.cfg

Una vez que el kernel de Linux se inicia con el parámetro isolcpus, el programador de equilibrio de tareas del kernel de Linux ya no programará el proceso en el núcleo de la CPU especificado. Los usuarios generalmente necesitan usar el comando taskset o cset para vincular el proceso al núcleo de la CPU.

2. Introducción a la vinculación de CPU

1. Introducción al núcleo de la CPU

La tecnología Hyper-Threading (Hyper-Threading) utiliza instrucciones de hardware especiales para simular dos núcleos lógicos (núcleos de CPU) en dos chips físicos, de modo que un solo procesador pueda usar computación paralela a nivel de subprocesos y sea compatible con sistemas operativos multiproceso y El software reduce el tiempo de inactividad de la CPU y mejora la eficiencia operativa de la CPU.
La CPU física es la CPU instalada en la placa base de la computadora.
Una CPU lógica es un núcleo de CPU físico en una CPU física. Por lo general, una CPU física tiene varios núcleos físicos, es decir, hay varias CPU lógicas. Si se admite la tecnología Intel Hyper-Threading (HT), la CPU lógica se puede dividir en el doble de la cantidad de núcleos de CPU.
cat /proc/cpuinfo|grep "physical id"|sort -u|wc -l
Ver la cantidad de CPU físicas
cat /proc/cpuinfo|grep "cpu cores"|uniq
Ver la cantidad de núcleos en cada CPU física (es decir, la cantidad de núcleos)
cat /proc/cpuinfo|grep "processor"|wc -l
Ver la cantidad de CPU lógicas
cat /proc/cpuinfo|grep "name"|cut -f2 -d:|uniq
Ver el nombre y modelo de la CPU Ver la CPU lógica que
ps -eo pid,args,psr
está ejecutando el proceso

2. Introducción a la vinculación de CPU

El enlace de CPU es para establecer la afinidad de CPU correspondiente para el proceso o subproceso para garantizar que el proceso o subproceso solo se ejecutará en la CPU con el bit de bandera correspondiente establecido, mejorando así la eficiencia del uso de la CPU por parte de la aplicación. Si la aplicación se puede ejecutar en varias CPU, el sistema operativo cambiará con frecuencia las aplicaciones entre las CPU, lo que hará que la memoria caché de la CPU deje de ser válida, lo que reducirá la tasa de aciertos de la memoria caché y provocará una disminución en la eficiencia del uso de la CPU. El uso de la tecnología de enlace de CPU puede evitar hasta cierto punto el fallo de la caché de la CPU y mejorar el rendimiento del sistema.
La afinidad de CPU es una propiedad de programación (propiedad del programador), que puede vincular un proceso a una o un grupo de CPU.
Bajo la arquitectura SMP (multiprocesamiento simétrico), el programador de Linux (programador) hará que el proceso especificado se ejecute en la CPU vinculada de acuerdo con la configuración de afinidad de la CPU, en lugar de ejecutarse en otras CPU.,
Programador de Linux También es compatible con la afinidad natural de la CPU: el programador intentará mantener el proceso en ejecución en la misma CPU, lo que significa que el proceso generalmente no migra con frecuencia entre procesadores, y la frecuencia de la migración del proceso significa que La carga es pequeña.
Debido a que el autor del programa conoce el programa mejor que el programador, podemos asignarle núcleos de CPU manualmente sin ocupar demasiado CPU0, o dejar que nuestro proceso clave y un montón de otros procesos se aprieten juntos, todos configuran la CPU Affinity puede hacer que ciertos programas mejoren el rendimiento.
El programador de procesos del kernel de Linux tiene una afinidad de CPU inherentemente suave (afinidad) y, por lo general, los procesos no migran con frecuencia entre procesadores.
Ver la asignación de CPU de todos los procesos Ver la asignación
ps -eo pid,cmd,psr
de CPU de todos los subprocesos del proceso
ps -To 'pid,lwp,psr,cmd' -p [PID]

3. Características del enlace de CPU

La vinculación de procesos / subprocesos a la CPU puede aumentar significativamente la tasa de aciertos de la caché de la CPU, lo que reduce la pérdida de acceso a la memoria y mejora el rendimiento de la aplicación. Creo que bajo la arquitectura NUMA, esta operación tiene un mayor significado para la mejora de la velocidad de operación del sistema, mientras que bajo la arquitectura SMP, esta mejora puede ser relativamente pequeña. Esto se debe principalmente a los diferentes métodos de asignación y uso de los recursos de caché y bus entre los dos. Bajo la arquitectura NUMA, cada CPU tiene su propio conjunto de sistemas de recursos; bajo la arquitectura SMP, cada núcleo aún necesita compartir estos recursos.
Cuando cada núcleo de CPU ejecuta un proceso, debido a que los recursos de cada proceso son independientes, no hay necesidad de considerar el contexto al cambiar entre núcleos de CPU; cuando cada núcleo de CPU ejecuta un hilo, a veces los hilos necesitan compartir recursos, por lo que Los recursos compartidos deben copiarse de un núcleo de la CPU a otro, lo que genera una sobrecarga adicional.

4. Proceso de vinculación del conjunto de tareas

yum install util-linux
Instale la herramienta de conjunto de tareas para
taskset [options] [mask] -p pid
ver la afinidad de CPU del proceso, use la opción -p para especificar el PID e imprima el número hexadecimal por defecto, si especifica la opción -cp para imprimir la lista de núcleos de CPU. La forma binaria de 3 es 0011, correspondiente a -cp imprime 0 y 1, lo que indica que el proceso solo puede ejecutarse en los núcleos 0 y 1 de la CPU.
taskset -c -p pid
Ver la afinidad de la CPU del proceso especificado

taskset -p mask pid
taskset -c [CPU NUMBER] -p PID

Establezca la afinidad de CPU del proceso especificado. Para CPU aisladas, solo la primera CPU es válida.
Utilice la CPU n. ° 11, 12, 13, 14, 15 para ejecutar el proceso

taskset -c 11,12,13,14,15 python xx.py
taskset -c 11-15 python xx.py

En los contenedores Docker, aún se pueden usar CPU aisladas; al crear un contenedor Docker, puede especificar qué CPU solo puede usar el contenedor a través del parámetro --cpuset-cpus, para lograr CPU aisladas en el contenedor Docker.

5. Proceso de vinculación de Cset

cset set --cpu CPU CPUSET NAME
Defina el conjunto de núcleos de CPU. Para una CPU independiente, solo el primer núcleo de CPU es válido.
cset proc --move --pid=PID,...,PID --toset=CPUSET NAME
Mover varios procesos al conjunto de CPU especificado

Tres, CPU de enlace de proceso

1. API de llamada al sistema

#define _GNU_SOURCE        
#include <sched.h>
int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);

Parámetros:
pid: número de proceso, si el valor pid es 0, significa que se especifica el proceso actual.
cpusetsize: la longitud del número especificado por el parámetro de máscara, generalmente establecido en sizeof (cpu_set_t).
máscara: máscara de CPU

2. Realización de la programación

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/sysinfo.h>
#include<unistd.h>

#define __USE_GNU
#include<sched.h>
#include<ctype.h>
#include<string.h>
#include<pthread.h>

#define THREAD_MAX_NUM 10  //1个CPU内的最多进程数
int CPU_NUM = 0;  //cpu中核数
int CPU = 3; // CPU编号

void* threadFun(void* arg)
{
    cpu_set_t mask;  //CPU核的集合

    CPU_ZERO(&mask);
    // set CPU MASK
    CPU_SET(CPU, &mask);
    //设置当前进程的CPU Affinity
    if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
    {
        printf("warning: could not set CPU affinity, continuing...\n");
    }
    cpu_set_t affinity;   //获取在集合中的CPU
    CPU_ZERO(&affinity);
    // 获取当前进程的CPU Affinity
    if (sched_getaffinity(0, sizeof(affinity), &affinity) == -1)
    {
        printf("warning: cound not get Process affinity, continuing...\n");
    }
    int i = 0;
    for (i = 0; i < CPU_NUM; i++)
    {
        if (CPU_ISSET(i, &affinity))//判断线程与哪个CPU有亲和力
        {
            printf("this thread %d is running processor : %d\n", *((int*)arg), i);
        }
    }

    return NULL;
}

int main(int argc, char* argv[])
{
    int tid[THREAD_MAX_NUM];
    pthread_t thread[THREAD_MAX_NUM];
    // 获取核数
    CPU_NUM = sysconf(_SC_NPROCESSORS_CONF);
    printf("System has %i processor(s). \n", CPU_NUM);
    int i = 0;
    for(i=0;i<THREAD_MAX_NUM;i++)
    {
        tid[i] = i;
        pthread_create(&thread[i],NULL,threadFun, &tid[i]);
    }
    for(i=0; i< THREAD_MAX_NUM; i++)
    {
        pthread_join(thread[i],NULL);
    }
    return 0;
}

Compilar:
gcc -o test test.c -pthread
ejecutar resultados:

System has 4 processor(s). 
this thread 1 is running processor : 3
this thread 0 is running processor : 3
this thread 4 is running processor : 3
this thread 9 is running processor : 3
this thread 7 is running processor : 3
this thread 5 is running processor : 3
this thread 6 is running processor : 3
this thread 8 is running processor : 3
this thread 3 is running processor : 3
this thread 2 is running processor : 3

3. El conjunto de tareas vincula el proceso a la CPU

(1) Vincular el proceso a la CPU especificada

taskset -pc CPU_NUMBER  PID
taskset -p PID

Verifique la Afinidad de CPU del proceso
(2) Cuando el proceso comience, vincule a la CPU para
taskset -c CPU_NUMBER PROGRAM&
iniciar el programa PROGRAM para que se ejecute en segundo plano, vincule el proceso al núcleo CPU_NUMBER y
taskset -p PID
verifique la Afinidad de CPU del proceso

Cuatro, CPU de enlace de subprocesos

1. API de llamada al sistema

#define _GNU_SOURCE            
#include <pthread.h>
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset)

Parámetros:
pthead: thread object
cpusetsize: la longitud del número especificado por el parámetro de máscara, generalmente establecido en sizeof (cpu_set_t).
máscara: máscara de CPU

2. Realización de la programación

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/sysinfo.h>
#include<unistd.h>

#define __USE_GNU
#include<sched.h>
#include<ctype.h>
#include<string.h>
#include<pthread.h>

#define THREAD_MAX_NUM 10  //1个CPU内的最多进程数
int CPU_NUM = 0;  //cpu中核数
int CPU = 3; // CPU编号

void* threadFun(void* arg)
{
    cpu_set_t affinity;   //获取在集合中的CPU
    CPU_ZERO(&affinity);
    pthread_t thread = pthread_self();
    // 获取当前进程的CPU Affinity
    if (pthread_getaffinity_np(thread, sizeof(affinity), &affinity) == -1)
    {
        printf("warning: cound not get Process affinity, continuing...\n");
    }
    int i = 0;
    for (i = 0; i < CPU_NUM; i++)
    {
        if (CPU_ISSET(i, &affinity))//判断线程与哪个CPU有亲和力
        {
            printf("this thread %d is running processor : %d\n", *((int*)arg), i);
        }
    }

    return NULL;
}

int main(int argc, char* argv[])
{
    int tid[THREAD_MAX_NUM];
    pthread_t thread[THREAD_MAX_NUM];
    // 获取核数
    CPU_NUM = sysconf(_SC_NPROCESSORS_CONF);
    printf("System has %i processor(s). \n", CPU_NUM);
    cpu_set_t mask;  //CPU核的集合

    CPU_ZERO(&mask);
    // set CPU MASK
    CPU_SET(CPU, &mask);

    int i = 0;
    for(i=0;i<THREAD_MAX_NUM;i++)
    {
        tid[i] = i;
        pthread_create(&thread[i],NULL,threadFun, &tid[i]);
        //设置当前进程的CPU Affinity
        if (pthread_setaffinity_np(thread[i], sizeof(mask), &mask) != 0)
        {
            printf("warning: could not set CPU affinity, continuing...\n");
        }
    }
    for(i=0; i< THREAD_MAX_NUM; i++)
    {
        pthread_join(thread[i],NULL);
    }
    return 0;
}

Compilar:
gcc -o test test.c -pthread
ejecutar resultados:

System has 4 processor(s). 
this thread 0 is running processor : 3
this thread 1 is running processor : 3
this thread 2 is running processor : 3
this thread 3 is running processor : 3
this thread 5 is running processor : 3
this thread 4 is running processor : 3
this thread 6 is running processor : 3
this thread 9 is running processor : 3
this thread 7 is running processor : 3
this thread 8 is running processor : 3

Supongo que te gusta

Origin blog.51cto.com/9291927/2594336
Recomendado
Clasificación