在C++(LINUX)中从另一个程序获取程序的内存使用情况

whhtz7ly  于 2023-01-18  发布在  Linux
关注(0)|答案(1)|浏览(102)

我想在gen.exe生成的随机测试中测量abc.exe的最大内存使用量。我该怎么做?
我在gen.exe的测试中运行abc.exe的代码如下所示:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int i = 0;
    while (true)
    {
        string si = to_string(i);
        cout << i << "\n";
        if (system(("echo " + si + "| ./gen.exe > test.in").c_str())) // gen.exe is test generator
        {
            cout << "gen error\n";
            break;
        }
        if (system(("./abc.exe < test.in > a.out"))) // abc.exe is the program I want to test
        {
            cout << "abc error\n";
            break;
        }
        i++;
    }
}

我知道我可以使用time -v ./abc.exe,但使用的内存会在终端中打印出来,但我希望能够将其保存到变量中。

a0zr77ik

a0zr77ik1#

可以使用getrusage( RUSAGE_CHILDREN, ... )来获取最大的驻留内存,注意这个调用将返回最大的子进程在那个时间点使用的最大内存。
在下面的例子中,我使用了boost::process,因为它提供了更好的控制,但它取决于你是否使用std::system,工作方式是一样的。

#include <string>
#include <cstdint>
#include <string.h>
#include <iostream>
#include <boost/process/child.hpp>
#include <sys/resource.h>

namespace bp = boost::process;

int parent( const std::string& exename )
{
    // Loop from 0 to 10 megabytes
    for ( int j=0; j<10; ++j )
    {
        // Command name is the name of this executable plus one argument with size
        std::string gencmd = exename + " " + std::to_string(j);

        // Start process
        bp::child child( gencmd );

        // Wait for it to allocate memory
        sleep(1);

        // Query the memory usage at this point in time
        struct rusage ru;
        getrusage( RUSAGE_CHILDREN, &ru );
        std::cerr << "Loop:" << j << " mem:"<< ru.ru_maxrss/1024. << " MB" << std::endl;

        // Wait for process to quit
        child.wait();
        if ( child.exit_code()!=0 )
        {
            std::cerr << "Error executing child:" << child.exit_code() << std::endl;
            return 1;
        }
    }
    return 0;
}

int child( int size ) {
    // Allocated "size" megabites explicitly
    size_t memsize = size*1024*1024;
    uint8_t* ptr = (uint8_t*)malloc( memsize );
    memset( ptr, size, memsize );

    // Wait for the parent to sample our memory usage
    sleep( 2 );

    // Free memory
    free( ptr );

    return 0;
}

int main( int argc, char* argv[] )
{
    // Without arguments, it is the parent. 
    // Pass the name of the binary 
    if ( argc==1 ) return parent( argv[0] );
    return child( std::atoi( argv[1] ) );
}

它打印

$ ./env_test 
Loop:0 mem:0 MB
Loop:1 mem:3.5625 MB
Loop:2 mem:4.01953 MB
Loop:3 mem:5.05469 MB
Loop:4 mem:6.04688 MB
Loop:5 mem:7.05078 MB
Loop:6 mem:7.78516 MB
Loop:7 mem:8.97266 MB
Loop:8 mem:9.82031 MB
Loop:9 mem:10.8867 MB

如果你不能使用boost库,你就得多做一点工作,但这仍然是可行的。
如果你只想知道你的子进程的最大大小,那么下面的std::system

#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>

#include <string.h>
#include <unistd.h>
#include <sys/resource.h>

int main(int argc, char* argv[]) {
    if (argc > 1) {
        size_t size = ::atol(argv[1]);
        size_t memsize = size * 1024 * 1024;
        void* ptr = ::malloc(memsize);
        memset(ptr, 0, memsize);
        ::sleep(2);
        ::free(ptr);
        return 0;
    }

    for (int j = 0; j < 10; ++j) {
        std::ostringstream cmd;
        cmd << argv[0] << " " << j;
        int res = std::system(cmd.str().c_str());
        if (res < 0) {
            fprintf(stderr, "ERROR system: %s\n", strerror(errno));
            break;
        }
        struct rusage ru;
        res = getrusage(RUSAGE_CHILDREN, &ru);
        size_t maxmem = ru.ru_maxrss;
        fprintf(stderr, "Loop:%d MaxMem:%ld\n", j, maxmem);
    }
    return 0;
}

它打印

Loop:0 MaxMem:3552
Loop:1 MaxMem:4192
Loop:2 MaxMem:5148
Loop:3 MaxMem:6228
Loop:4 MaxMem:7364
Loop:5 MaxMem:8456
Loop:6 MaxMem:9120
Loop:7 MaxMem:10188
Loop:8 MaxMem:11324
Loop:9 MaxMem:12256

但是,如果您想跟踪子进程执行期间的内存使用情况,则不能使用std::system()。首先,您需要调用fork()来生成一个新进程,然后调用execv()来执行bash命令。

#include <string>
#include <cstdint>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <sys/resource.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <vector>

int parent(const std::string& exename) {
    // Loop from 0 to 10 megabytes
    for (int j = 0; j < 10; ++j) {
        // Command name is the name of this executable plus one argument with size
        std::string gencmd = exename + " " + std::to_string(j);

        // Start process
        pid_t pid = fork();
        if (pid == 0) {  // child
            const char* args[] = {"/bin/bash", "-c", gencmd.c_str(), (char*)0};
            int res = execv("/bin/bash", (char**)args);
            // Should never return
            std::cerr << "execv error: " << strerror(errno) << std::endl;
            return 1;
        }

        // parent
        long maxmem = 0;
        while (true) {
            int status;
            pid_t rid = ::waitpid(pid, &status, WNOHANG);
            if (rid < 0) {
                if (errno != ECHILD) {
                    std::cerr << "waitpid:" << strerror(errno) << std::endl;
                    return 2;
                }
                break;
            }
            if (rid == pid) {
                if (WIFEXITED(pid)) {
                    break;
                }
            }

            // Wait for it to allocate memory
            usleep(10000);

            // Query the memory usage at this point in time
            struct rusage ru;
            int res = getrusage(RUSAGE_CHILDREN, &ru);
            if (res != 0) {
                if (errno != ECHILD) {
                    std::cerr << "getrusage:" << errno << strerror(errno) << std::endl;
                }
                break;
            }
            if (maxmem < ru.ru_maxrss) {
                maxmem = ru.ru_maxrss;
            }
        }
        std::cerr << "Loop:" << j << " mem:" << maxmem / 1024. << " MB" << std::endl;
    }
    return 0;
}

int child(int size) {
    // Allocated "size" megabites explicitly
    size_t memsize = size * 1024 * 1024;
    uint8_t* ptr = (uint8_t*)malloc(memsize);
    memset(ptr, size, memsize);

    // Wait for the parent to sample our memory usage
    sleep(2);

    // Free memory
    free(ptr);

    return 0;
}

int main(int argc, char* argv[]) {
    // Without arguments, it is the parent.
    // Pass the name of the binary
    if (argc == 1) return parent(argv[0]);
    return child(std::atoi(argv[1]));
}

我的计算机上的结果是:

$ ./fork_test 
Loop:0 mem:3.22656 MB
Loop:1 mem:3.69922 MB
Loop:2 mem:4.80859 MB
Loop:3 mem:5.92578 MB
Loop:4 mem:6.87109 MB
Loop:5 mem:8.05469 MB
Loop:6 mem:8.77344 MB
Loop:7 mem:9.71875 MB
Loop:8 mem:10.7422 MB
Loop:9 mem:11.6797 MB

有关于这个帖子的a video

相关问题