Reputation: 2218
Is there a simple way to get the number of files opened by a c++ program.
I would like to do it from my code, ideally in C++.
I found this blog article which is using a loop through all the available file descriptor and testing the result of fstat
, but I am wondering if there is any simpler way to do that.
Upvotes: 7
Views: 4942
Reputation: 2704
This is a legitimate question: I count open file descriptors in unit tests to verify none has leaked. On Linux systems there's one entry in /proc/self/fd
for each open file descriptor, so you just have to count them. In c++17 it looks like this:
long file_descriptor_count() {
return std::distance(std::filesystem::directory_iterator("/proc/self/fd"), std::filesystem::directory_iterator{});
}
Upvotes: 5
Reputation: 860
There is a good practice that the scope of file opened in the smallest possible, open dump all information you want, or buffer into the fd
, then close.
So, this means the usual case, we will have 3 fd
s, the std
in
/out
/err
, plus all opened files.
Keep track of your open files manually is the best, if you keep files opened.
Put a global fdCounter
variable, increment it after a successful file open, decremented after closing.
Upvotes: 0
Reputation: 782
In my experience, by the time you need to count the number of file descriptors, you don't know where they were opened, by what submodule or library. Thus, wrapping open/close is not a viable strategy. Brute-force counting seems to be the only way.
The domain with the orig blog post no longer resolves in DNS. I copy two proposals from Find current number of open filehandle ( NOT lsof )
int j, n = 0;
// count open file descriptors
for (j = 0; j < FDMAX; ++j) // FDMAX should be retrieved from process limits,
// but a constant value of >=4K should be
// adequate for most systems
{
int fd = dup (j);
if (fd < 0)
continue;
++n;
close (fd);
}
printf ("%d file descriptors open\n", n);
and also this:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main (void)
{
DIR *dp;
struct dirent *ep;
dp = opendir ("/proc/MYPID/fd/");
if (dp != NULL)
{
while (ep = readdir (dp))
puts (ep->d_name);
(void) closedir (dp);
}
else
perror ("Couldn't open the directory");
return 0;
}
Upvotes: 0
Reputation: 22084
If you encapsulated it properly, it should be simple to add reference counters or logging to it and print them to the console.
One approach to debug it is to override the open calls with your own implementation and from there call the real thing. Then you can also put some logging in, to see if you loose file descriptors. How do you open the files? With open()
or are you using fopen()
?
Something like this maybe:
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <fcntl.h>
inline int log_open(char *p, int flags, int mode)
{
int fd = ::open(p, flags, mode);
std::cout << "OPEN: " << fd << std::endl;
return fd;
}
inline int log_close(int fd)
{
int rc = ::close(fd);
std::cout << "CLOSE: " << fd << std::endl;
return rc;
}
#define open(p, f, m) log_open(p, f, m)
#define close(fd) log_close(fd)
int main(int argc, char *argv[])
{
int fd = open("tmp.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
std::cout << "FD: " << fd << std::endl;
if(fd != -1)
close(fd);
return 0;
}
Upvotes: 0
Reputation: 129344
Since the files are FILE *
, we could do something like this:
In a headerfile that gets included everywhere:
#define fopen(x, y) debug_fopen(x, y, __FILE__, __LINE__)
#define fclose(x) debug_fclose(x)
in "debugfile.cpp" (must obviously NOT use the above #define
's)
struct FileInfo
{
FileInfo(const char *nm, const char fl, int ln) :
name(nm), file(fl), line(ln) {}
std::string name;
const char *file;
int line;
};
std::map<FILE*, FileInfo> filemap;
FILE *debug_fopen(const char *fname, const char *mode, const char *file, int line)
{
FILE *f = fopen(fname, mode);
if (f)
{
FileInfo inf(fname, file, line);
filemap[f] = inf;
}
}
int debug_fclose(FILE *f)
{
int res = fclose(f);
filemap.erase(f);
return res;
}
// Called at some points.
void debug_list_openfiles()
{
for( i : filemap )
{
cerr << "File" << (void *) i.first << " opened as " << i.second.name
<< " at " << i.second.file << ":" << i.second.line << endl;
}
}
(I haven't compiled this code, and it's meant to show the concept, it may have minor bugs, but I think the concept would hold - as long as your code, and not some third party library is leaking)
Upvotes: 2
Reputation: 3369
If you are under linux, this information is available under /proc/you_pid/fd
.
Then use, lstat
on each file descriptor to keep only regular files.
Upvotes: 0