Неожиданная пропускная способность с тестом TCP в C - PullRequest
0 голосов
/ 11 апреля 2020

Итак, я провожу некоторые тесты TCP для изучения влияния количества данных, передаваемых за соединение, на результирующую пропускную способность. Поэтому я написал сервер и клиент в C, чтобы измерить то, что мне нужно. Затем я использовал сценарий Python для многократного запуска экспериментов (чтобы получить точность +/- 1%, я запускал свой тест в течение 100 с. Для каждой точки данных я проводил эксперимент 33 раза, чтобы получить приличное среднее значение.) с разными входами и для сбора результатов.

Результаты, которые я получаю, кажутся правильными (я могу даже наблюдать ожидаемое плато при больших объемах данных, передаваемых по соединению), за исключением того, что пропускная способность составляет всего 10 % от того, что должно быть ...

Поскольку у меня есть доступ только к одному компьютеру для запуска этого теста, я выполняю тесты на локальном хосте, но это не должно быть проблемой.

Вот мои результаты:

Graph of benchmark results

Как видите, лучшая пропускная способность, которую я могу получить, составляет чуть более 300 МБ / с ... Но если я запустить тест пропускной способности с помощью iperf (я удостоверился, что использовал тот же размер окна TCP), на локальном хосте я получил пропускную способность около 3 ГБ / с.

Вот код моего клиента:

int main(int argc, char const *argv[])
{
    unsigned int size;
    unsigned int timeout;
    int sockfd;
    struct sockaddr_in server_addr;

    if(argc < 4 || argc > 5 ){
        usage();
        exit(1);
    }

    const char * ip = "127.0.0.1";
    ip = argv[3];

    int port = PORT;
    if(argc == 5) {
        port = atoi(argv[4]);
    }

    size = atoi(argv[1]);
    timeout = atoi(argv[2]);

    unsigned int count = 0;

    struct timespec start, end;

    clock_gettime(CLOCK_MONOTONIC_RAW, &start);
    clock_gettime(CLOCK_MONOTONIC_RAW, &end);

    while((end.tv_sec - start.tv_sec) < timeout) {

        // socket create and varification
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1) {
            perror("Could not create socket\n");
            exit(0);
        }

        bzero(&server_addr, sizeof(server_addr));

        // assign IP, PORT of the server
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = inet_addr(ip);
        server_addr.sin_port = htons(port);

        // connect the client socket to server socket
        if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
            perror("connection with the server failed");
            exit(1);
        }

        unsigned int nread = 0;
        unsigned int nreadcum = 0;
        char* buf = malloc(size);
        char* bufbuf = buf;

        while(nreadcum < size){
            nread = read(sockfd, bufbuf, size-nreadcum);
            nreadcum += nread;
            bufbuf+=nread;
        }
        // close connection
        close(sockfd);
        count++;
        clock_gettime(CLOCK_MONOTONIC_RAW, &end);
        free(buf);
    }


    uint64_t sec = (end.tv_sec - start.tv_sec);
    double bandwidth = (count*size)/sec;

    printf("%u,%lf,%u,%lu\n", size, bandwidth, count, sec);

    return 0;
}

А вот код моего сервера:

* 101 8 *

В основном мой код выполняет следующие действия:

  • для сервера: дождитесь подключения клиента, отправьте фиктивную полезную нагрузку требуемого размера и закройте соединение с этим клиентом, повторите .
  • для клиента: откройте соединение с сервером, прочитайте то, что отправляет сервер, пока сервер не закроет соединение, повторите до тех пор, пока не будет достигнуто установленное время ожидания.

Для расчета пропускную способность, я могу просто сделать (number_of_connections_completed * size_transferred_by_connection) / duration_of_all_transfers. Я использую python для расчета пропускной способности, чтобы избежать переполнения в C.

TLDR: Пропускная способность, которую я получаю с моими C программами, в 10 раз меньше, чем что это должно быть на localhost. Что может быть источником этой проблемы?

1 Ответ

0 голосов
/ 11 апреля 2020

malloc и free являются основными проблемами здесь. Так как они являются системными вызовами, они занимают значительное количество времени, и поскольку я измеряю производительность TCP, а не производительность выделения памяти, malloc и free должны быть вне моего профиля l oop. Кроме того, то же самое относится к printf на стороне сервера l oop, хотя не так плохо, как malloc, время, которое требуется для печати чего-либо на экране, не является тем, что следует учитывать при измерении производительность по TCP.

...