2012-06-05 12 views
19

sto vedendo un paio di cose strane con un paio di prese AF_UNIX create da una chiamata come ad esempio:AF_UNIX sovraccarico?

socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

Dove sfd è un int [2] array per i descrittori di file.

In primo luogo, la dimensione del buffer di default sembra essere esattamente 122K (124928 byte), piuttosto che qualsiasi cosa da/proc/sys/net (come wmem_default che è impostato su 128K). Qualcuno conosce la causa di questa strana dimensione del buffer?

Secondo, quando si scrivono piccoli messaggi attraverso il socket (8 byte). Posso solo scrivere 423 di loro prima dei blocchi di scrittura, che è solo 8 * 423 = 3384 byte, un'altra dimensione dispari. I messaggi agiscono come se stessero prendendo 295 + un piccolo byte ciascuno. Qual è la fonte di questo sovraccarico?

Running on RHEL6 (2.6.32, 64-bit)

ho scritto un programma per provare diverse dimensioni di dati per confrontare i costi generali:

#include <errno.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

#define DATA_SIZE 4 

void run(size_t size) { 
    int sfd[2]; 
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { 
     perror("error"); 
    } 


    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Data Size: %zd\n", size); 
    char buff[size]; 
    size_t wrote=0; 
    for (size_t ii=0; ii < 32768; ii++) { 
     if ((send(sfd[0], buff, size, MSG_DONTWAIT) == -1) && (errno == EAGAIN)) { 
      wrote = ii; 
      break; 
     } 
    } 

    printf("Wrote:  %zd\n", wrote); 

    if (wrote != 0) { 
     int bpm = sndbuf/wrote; 
     int oh = bpm - size; 

     printf("Bytes/msg: %i\n", bpm); 
     printf("Overhead: %i\n", oh); 
     printf("\n"); 
    } 

    close(sfd[0]); close(sfd[1]); 
} 

int main() { 
    int sfd[2]; 
    socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Buffer Size: %i\n\n", sndbuf); 
    close(sfd[0]); close(sfd[1]); 

    for (size_t ii=4; ii <= 4096; ii *= 2) { 
     run(ii); 
    } 
} 

che dà:

Buffer Size: 124928 

Data Size: 4 
Wrote:  423 
Bytes/msg: 295 
Overhead: 291 

Data Size: 8 
Wrote:  423 
Bytes/msg: 295 
Overhead: 287 

Data Size: 16 
Wrote:  423 
Bytes/msg: 295 
Overhead: 279 

Data Size: 32 
Wrote:  423 
Bytes/msg: 295 
Overhead: 263 

Data Size: 64 
Wrote:  423 
Bytes/msg: 295 
Overhead: 231 

Data Size: 128 
Wrote:  348 
Bytes/msg: 358 
Overhead: 230 

Data Size: 256 
Wrote:  256 
Bytes/msg: 488 
Overhead: 232 

Data Size: 512 
Wrote:  168 
Bytes/msg: 743 
Overhead: 231 

Data Size: 1024 
Wrote:  100 
Bytes/msg: 1249 
Overhead: 225 

Data Size: 2048 
Wrote:  55 
Bytes/msg: 2271 
Overhead: 223 

Data Size: 4096 
Wrote:  29 
Bytes/msg: 4307 
Overhead: 211 

Rispetto all'utilizzo di un tubo ci sono sicuramente un sacco di spese generali:

Data Size: 4 
Wrote:  16384 
Bytes/msg: 4 
Overhead: 0 

Data Size: 8 
Wrote:  8192 
Bytes/msg: 8 
Overhead: 0 

Data Size: 16 
Wrote:  4096 
Bytes/msg: 16 
Overhead: 0 

Data Size: 32 
Wrote:  2048 
Bytes/msg: 32 
Overhead: 0 

Data Size: 64 
Wrote:  1024 
Bytes/msg: 64 
Overhead: 0 

Data Size: 128 
Wrote:  512 
Bytes/msg: 128 
Overhead: 0 

Data Size: 256 
Wrote:  256 
Bytes/msg: 256 
Overhead: 0 

Data Size: 512 
Wrote:  128 
Bytes/msg: 512 
Overhead: 0 

Data Size: 1024 
Wrote:  64 
Bytes/msg: 1024 
Overhead: 0 

Data Size: 2048 
Wrote:  32 
Bytes/msg: 2048 
Overhead: 0 

Data Size: 4096 
Wrote:  16 
Bytes/msg: 4096 
Overhead: 0 
+0

send() restituisce il numero di byte effettivamente scritto. Dovresti sommare questi, non solo assumendo che sia stato scritto tutto. – EJP

+1

Nel peggiore dei casi, avrò scritto meno di quello che sto rivendicando, il che renderebbe ancora più grave il sovraccarico sul socket del dominio. –

risposta

1

Hai visto il valore della sysctl net.unix.max_dgram_qlen?

Il kernel impone un limite al numero massimo di datagrammi AF_UNIX in volo. Sul mio sistema il limite è in realtà molto basso: solo 10.

+0

Non ne ero al corrente, no. Ciò si applica qui però, dal momento che sto cantando un tipo SOCK_STREAM? –

+1

No, dovrebbe applicarsi solo ai socket dei datagrammi, almeno nella versione del kernel che sto guardando. –

+1

Infatti, non riesco a capire perché una scrittura di un datagramma Unix possa mai essere breve se si colpisce wmem_max. –

5

Dai un'occhiata alla pagina man di socket (7). C'è una sezione che legge:

SO_SNDBUF Imposta o ottiene il buffer di invio socket massimo in byte. Il kernel raddoppia questo valore (per consentire lo spazio per il carico contabile) quando è impostato utilizzando setsockopt (2), e questo valore raddoppiato viene restituito da getsockopt (2). Il valore predefinito è impostato dal file /proc/sys/net/core/wmem_default e il valore massimo consentito è impostato dal file /proc/sys/net/core/wmem_max. Il valore minimo (raddoppiato) per questa opzione è 2048.

così sembra che il sovraccarico è semplicemente quello di tenere le informazioni per il kernel contabilità.

+0

Non sono nemmeno sicuro che si applichi ai socket locali, e un dimezzamento dello spazio del buffer disponibile non dovrebbe ancora tenere conto di tutto il sovraccarico che sto vedendo. –

+1

La pagina man non distingue tra AF_UNIX o i domini non locali, quindi presumo che si applichi su tutta la linea. Questa è tutta la documentazione che sono stato in grado di trovare riguardo alla situazione. Sospetto che se hai bisogno di sapere "esattamente" su cosa è usato il sovraccarico, dovrai dare un'occhiata al codice di rete del kernel. – Chimera

+1

Non ho accettato questa risposta perché penso che anche con il fattore-di-due in testa, sto ancora vedendo troppo per-messaggio. Anche se il kernel mi permettesse solo di usare 62464 byte, dovrei essere in grado di scrivere oltre 15000 messaggi prima di riempire il buffer, e ne vedo solo 1/30. –