8359706: Add file descriptor count to VM.info

Reviewed-by: kevinw, stuefe
This commit is contained in:
Kieran Farrell 2026-03-17 06:00:32 +00:00 committed by Thomas Stuefe
parent a1e4621b30
commit b0831572e2
8 changed files with 105 additions and 1 deletions

View File

@ -2667,3 +2667,7 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
void os::jfr_report_memory_info() {}
#endif // INCLUDE_JFR
void os::print_open_file_descriptors(outputStream* st) {
// File descriptor counting not implemented on AIX
}

View File

@ -76,6 +76,7 @@
# include <fcntl.h>
# include <fenv.h>
# include <inttypes.h>
# include <mach/mach.h>
# include <poll.h>
# include <pthread.h>
# include <pwd.h>
@ -102,6 +103,7 @@
#endif
#ifdef __APPLE__
#include <libproc.h>
#include <mach/task_info.h>
#include <mach-o/dyld.h>
#endif
@ -2596,3 +2598,45 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
return res;
} // end: os::pd_dll_unload()
void os::print_open_file_descriptors(outputStream* st) {
#ifdef __APPLE__
char buf[1024 * sizeof(struct proc_fdinfo)];
os::Bsd::print_open_file_descriptors(st, buf, sizeof(buf));
#else
st->print_cr("Open File Descriptors: unknown");
#endif
}
void os::Bsd::print_open_file_descriptors(outputStream* st, char* buf, size_t buflen) {
#ifdef __APPLE__
pid_t my_pid;
// ensure the scratch buffer is big enough for at least one FD info struct
assert(buflen >= sizeof(struct proc_fdinfo));
kern_return_t kres = pid_for_task(mach_task_self(), &my_pid);
if (kres != KERN_SUCCESS) {
st->print_cr("Open File Descriptors: unknown");
return;
}
size_t max_fds = buflen / sizeof(struct proc_fdinfo);
struct proc_fdinfo* fds = reinterpret_cast<struct proc_fdinfo*>(buf);
// fill our buffer with FD info, up to the available buffer size
int res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, max_fds * sizeof(struct proc_fdinfo));
if (res <= 0) {
st->print_cr("Open File Descriptors: unknown");
return;
}
// print lower threshold if count exceeds buffer size
int nfiles = res / sizeof(struct proc_fdinfo);
if ((size_t)nfiles >= max_fds) {
st->print_cr("Open File Descriptors: > %zu", max_fds);
return;
}
st->print_cr("Open File Descriptors: %d", nfiles);
#else
st->print_cr("Open File Descriptors: unknown");
#endif
}

View File

@ -123,6 +123,8 @@ class os::Bsd {
static int get_node_by_cpu(int cpu_id);
static void print_uptime_info(outputStream* st);
static void print_open_file_descriptors(outputStream* st, char* buf, size_t buflen);
static void print_open_file_descriptors(outputStream* st);
};
#endif // OS_BSD_OS_BSD_HPP

View File

@ -83,6 +83,7 @@
#endif
# include <ctype.h>
# include <dirent.h>
# include <dlfcn.h>
# include <endian.h>
# include <errno.h>
@ -113,6 +114,7 @@
# include <sys/types.h>
# include <sys/utsname.h>
# include <syscall.h>
# include <time.h>
# include <unistd.h>
#ifdef __GLIBC__
# include <malloc.h>
@ -2161,6 +2163,8 @@ void os::print_os_info(outputStream* st) {
os::Posix::print_rlimit_info(st);
os::print_open_file_descriptors(st);
os::Posix::print_load_average(st);
st->cr();
@ -5429,3 +5433,33 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
return res;
} // end: os::pd_dll_unload()
void os::print_open_file_descriptors(outputStream* st) {
DIR* dirp = opendir("/proc/self/fd");
int fds = 0;
struct dirent* dentp;
const jlong TIMEOUT_NS = 50000000L; // 50 ms in nanoseconds
bool timed_out = false;
// limit proc file read to 50ms
jlong start = os::javaTimeNanos();
assert(dirp != nullptr, "No proc fs?");
while ((dentp = readdir(dirp)) != nullptr && !timed_out) {
if (isdigit(dentp->d_name[0])) fds++;
if (fds % 100 == 0) {
jlong now = os::javaTimeNanos();
if ((now - start) > TIMEOUT_NS) {
timed_out = true;
}
}
}
closedir(dirp);
if (timed_out) {
st->print_cr("Open File Descriptors: > %d", fds);
} else {
st->print_cr("Open File Descriptors: %d", fds);
}
}

View File

@ -6276,6 +6276,10 @@ const void* os::get_saved_assert_context(const void** sigInfo) {
return nullptr;
}
void os::print_open_file_descriptors(outputStream* st) {
// File descriptor counting not supported on Windows.
}
/*
* Windows/x64 does not use stack frames the way expected by Java:
* [1] in most cases, there is no frame pointer. All locals are addressed via RSP

View File

@ -893,6 +893,9 @@ class os: AllStatic {
static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
static void print_elapsed_time(outputStream* st, double time);
// Prints the number of open file descriptors for the current process
static void print_open_file_descriptors(outputStream* st);
static void print_user_info(outputStream* st);
static void print_active_locale(outputStream* st);

View File

@ -1329,6 +1329,13 @@ void VMError::report(outputStream* st, bool _verbose) {
STEP_IF("printing OS information", _verbose)
os::print_os_info(st);
st->cr();
#ifdef __APPLE__
// Avoid large stack allocation on Mac for FD count during signal-handling.
os::Bsd::print_open_file_descriptors(st, buf, sizeof(buf));
st->cr();
#else
os::print_open_file_descriptors(st);
#endif
STEP_IF("printing CPU info", _verbose)
os::print_cpu_info(st, buf, sizeof(buf));
@ -1550,6 +1557,8 @@ void VMError::print_vm_info(outputStream* st) {
os::print_os_info(st);
st->cr();
os::print_open_file_descriptors(st);
st->cr();
// STEP("printing CPU info")

View File

@ -33,7 +33,6 @@ import java.util.List;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
/*
* @test
@ -182,5 +181,10 @@ public class TestJcmdSanity {
output.shouldNotContain("*** Handler was modified!");
output.shouldNotContain("*** Expected: "); // e.g. *** Expected: javaSignalHandler in ...
}
// Should find file descriptor counting on Mac and Linux
if (Platform.isLinux() || Platform.isOSX()) {
output.shouldMatch("Open File Descriptors: \\d+");
}
}
}