A API de soquete fornece uma opção SO_INCOMING_CPU
, cujos detalhes são fornecidos no homem página :
SO_INCOMING_CPU (gettable since Linux 3.19, settable since Linux 4.4) Sets or gets the CPU affinity of a socket. Expects an integer flag. int cpu = 1; setsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, sizeof(cpu)); Because all of the packets for a single stream (i.e., all packets for the same 4-tuple) arrive on the single RX queue that is associated with a particular CPU, the typical use case is to employ one listening process per RX queue, with the incoming flow being handled by a listener on the same CPU that is handling the RX queue. This provides optimal NUMA behavior and keeps CPU caches hot.
Eu tenho um servidor que cria um soquete UDP, vincula a interface e recv()
s dados. Eu quero pegar o SO_INCOMING_CPU
deste soquete. Isso é possível?
Eu escrevi um programa de teste e o programa de teste retorna consistentemente -1.
Eu fiz uma depuração de printk()
, e parece que o problema é que não há um inet_daddr
associado ao soquete: link
Acho que isso faz sentido: o UDP é sem conexão e, como tal, o soquete pode receber pacotes de qualquer endereço. E acho que li em algum lugar que a afinidade da CPU de um soquete é uma função da tupla 4 e, assim, o soquete não tem necessariamente uma afinidade de CPU fixa.
No entanto, dado o fato de que existe um código para inicializar a afinidade da CPU no udp.c, acho que pode estar faltando alguma coisa.
Existe alguma maneira de obter SO_INCOMING_CPU
trabalhando com um soquete UDP do lado do servidor?
Aqui está o programa de teste (ligeiramente desleixado) que mencionei:
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("Error opening socket");
return 0;
}
struct sockaddr_in myaddr;
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(4242);
if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
#define BUFSIZE 20
unsigned char buf[BUFSIZE]; /* receive buffer */
struct sockaddr_in remaddr; /* remote address */
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen = recvfrom(sockfd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
sleep(1);
int cpu = 0;
socklen_t len = sizeof(cpu);
int ret = getsockopt(sockfd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, &len);
// Sample Output: Incoming CPU is -1 (ret = 0, recvlen = 5)
printf("Incoming CPU is %d (ret = %d, recvlen = %d)\n", cpu, ret, recvlen);
}
Tags networking c udp socket