0

File-descriptor creation in Linux takes considerable time at 256 and 512 values (~5 to ~15ms on my laptop). Otherwise it finishes avg. in <2us.

Also I noticed this problem happens only if its executed from a new thread. Its not possible to replicate this in main thread.

Is this expected? Why does it happening like this? Is it better to pool fds instead of closing and creating new?

Sample code:

#include <iostream>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <ctime>
#include <cerrno>
#include <cstring>
#include <thread>
#include <sstream>
#include <vector>

#define PER_THREAD   1000
#define THRESHOLD_NS 1'000'000   // 1 millisecond

inline long long duration_ns(const timespec& s, const timespec& e) {
    return (e.tv_sec - s.tv_sec) * 1'000'000'000LL + (e.tv_nsec - s.tv_nsec);
}

void eventfd_thread(int id) {
    std::vector<int> fds;
    fds.reserve(PER_THREAD);

    for (int i = 0; i < PER_THREAD; ++i) {
        timespec start{}, end{};
        clock_gettime(CLOCK_MONOTONIC, &start);
                int fd = eventfd(0, 0);
        clock_gettime(CLOCK_MONOTONIC, &end);

        if (fd == -1) {
            std::cerr << "[T" << id << "] ERROR: " << std::strerror(errno) << "\n";
            break;
        }

        long long dur_ns = duration_ns(start, end);
        double dur_ms = dur_ns / 1'000'000.0;

        if (dur_ns > THRESHOLD_NS) {
            std::ostringstream log;
            log.precision(3);
            log << std::fixed;
            log << "[T" << id << "] eventfd " << i << ": fd=" << fd
                << " | time=" << dur_ms << " ms";
            std::cout << log.str() << "\n";
        }

        fds.push_back(fd);
    }

    for (int fd : fds) close(fd);
    std::cout << "[T" << id << "] Closed " << fds.size() << " eventfds\n";
}

int main() {
    // eventfd_thread(1); // works fine

    std::thread t1(eventfd_thread, 1);
    t1.join();

    std::cout << "Done. Total eventfds created: " << PER_THREAD * 2 << "\n";
    return 0;
}

Output:

$ ./app
[T1] eventfd 253: fd=256 | time=19.344 ms
[T1] eventfd 509: fd=512 | time=11.142 ms
[T1] Closed 1000 eventfds
Done. Total eventfds created: 2000

The behavior is same if I try timerfd or epoll_create etc.

3
  • This behavior is likely to vary by version of the Linux kernel you're using. Suggest adding it and comparing some other kernel versions. Commented May 23 at 13:14
  • 8
    fs/file.c:169 Commented May 23 at 13:22
  • Maybe the kernel is allocating filedescriptors in chunks of 256 pieces a time, so you're basically seeing it expand the table size at multiples of 256... Commented May 24 at 9:18

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.