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.