簡體   English   中英

從 C++ (LINUX) 中的另一個程序獲取 memory 程序的用法

[英]Getting memory usage of program from another program in C++ (LINUX)

我想在 gen.exe 生成的隨機測試中測量 abc.exe 的最大使用量 memory。 我怎么能那樣做?

我在 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 但隨后使用的 memory 打印在終端中,但我希望能夠將其保存到變量中。

您可以使用getrusage( RUSAGE_CHILDREN, ... )獲取最大駐留 memory。請注意,此調用將返回最大孩子在該時間點使用的最大 memory。

在下面的示例中,我使用了 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

但是,如果您想在子進程執行期間跟蹤 memory 的使用情況,則不能使用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

一個關於這篇文章的視頻

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM