2012-06-05 5 views
19

Я вижу пару странные вещи с парой AF_UNIX розеток, созданных с помощью вызова, такие как:Накладные расходы на розетку AF_UNIX?

socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

Где SFD является ИНТ [2] массив для файловых дескрипторов.

Во-первых, размер буфера по умолчанию, по-видимому, составляет ровно 122 КБ (124928 байт), а не что-либо из/proc/sys/net (например, wmem_default, установленное на 128 КБ). Кто-нибудь знает причину этого странного размера буфера?

Во-вторых, при записи небольших сообщений через сокет (8 байтов). Я могу написать только 423 из них перед блоками записи, который составляет всего 8 * 423 = 3384 байта, еще один нечетный размер. Сообщения действуют так, как будто они занимают 295 + несколько байтов каждый. Каков источник этих накладных расходов?

Бег на RHEL6 (2.6.32, 64-битным)

Я написал программу, чтобы попробовать разные размеры данных сравнить накладные расходы:

#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); 
    } 
} 

Что дает:

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 

В сравнении с использованием трубы определенно много накладных расходов:

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() возвращает количество фактически записанных байтов. Вы должны их суммировать, а не только полагать, что все было написано. – EJP

+1

Худший случай Я напишу меньше, чем заявляю, что еще больше ухудшит накладные расходы на сокет. –

ответ

1

Вы просмотрели значение net.unix.max_dgram_qlen sysctl?

Ядро налагает ограничение на максимальное количество дейтаграмм AF_UNIX в полете. На моей системе предел на самом деле очень низкий: только 10.

+0

Я не знал об этом, нет. Будет ли это применяться здесь, хотя, так как я пою тип SOCK_STREAM? –

+1

Нет, это должно относиться только к сокетам дейтаграмм, по крайней мере, к версии ядра, на которую я смотрю. –

+1

На самом деле, я не понимаю, почему запись сокета datagram в UNIX будет когда-либо коротким, если вы нажмете wmem_max. –

5

Посмотрите на справочную страницу сокета (7). Существует раздел, который гласит:

SO_SNDBUF Устанавливает или получает максимальный буфер передачи сокета в байтах. Ядро удваивает это значение (чтобы освободить место для служебных накладных расходов), когда оно установлено с помощью setsockopt (2), и это значение возвращает значение getsockopt (2). Значение по умолчанию устанавливается файлом /proc/sys/net/core/wmem_default, а максимальное допустимое значение устанавливается файлом /proc/sys/net/core/wmem_max. (Вдвое) минимальное значение этого параметра составляет 2048.

Получается, что накладные расходы просто держать Бухгалтерская информация для ядра.

+0

Я даже не уверен, что это применимо к локальным сокетам, и простое сокращение пополам доступного пространства для буфера все равно не будет учитывать все накладные расходы, которые я вижу. –

+1

На странице руководства не проводится различие между AF_UNIX или нелокальными доменами, поэтому я предполагаю, что он применяется по всей доске. Вот и вся документация, которую я смог найти относительно ситуации. Я подозреваю, что вам нужно знать «точно», что для вас используется служебная информация, вам придется взглянуть на сетевой код ядра. – Chimera

+1

Я не принял этот ответ, потому что я думаю, что даже с накладными расходами «два-два» я все еще вижу слишком много для каждого сообщения. Даже если ядро ​​только позволяло мне использовать 62464 байт, тогда я должен был бы написать 15000+ сообщений до заполнения буфера, и я вижу только 1/30. –

Смежные вопросы