Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82a48b16 authored by Sandeep Patil's avatar Sandeep Patil
Browse files

meminfo: Add Smaps(), showmap and friends.



Needed by showmap and also android_s_Debug to classify each allocation
into multiple heaps.

The APIs added are:
ForEachVmaFromFile - Global API to parse a file expected to be in the
same format as /proc/<pid>/smaps and make a callback for each VMA found.
ProcMemInfo::ForEachVma - Same as 'ForEachVmaFromFile' but for a
ProcMemInfo object corresponding to a process(pid).
ProcMemInfo::Smaps - Wrapper to ProcMemInfo::ForEachVma, except the
function collects 'struct Vma' in a member vector and returns the
reference for the same.

Added showmap2 using the APIs and the corresponding tests the same time.

Bug: 111694435
Test: showmap_test.sh
Test: libmeminfo_test 1

Change-Id: I3065809cf94ecf3da88529809701035c47a8ce34
Signed-off-by: default avatarSandeep Patil <sspatil@google.com>
parent fa2d8d55
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


#pragma once
#pragma once


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


@@ -66,10 +67,16 @@ struct Vma {
    uint16_t flags;
    uint16_t flags;
    std::string name;
    std::string name;


    Vma() : start(0), end(0), offset(0), flags(0), name("") {}
    Vma(uint64_t s, uint64_t e, uint64_t off, uint16_t f, const char* n)
    Vma(uint64_t s, uint64_t e, uint64_t off, uint16_t f, const char* n)
        : start(s), end(e), offset(off), flags(f), name(n) {}
        : start(s), end(e), offset(off), flags(f), name(n) {}
    ~Vma() = default;
    ~Vma() = default;


    void clear() {
        memset(&usage, 0, sizeof(usage));
        memset(&wss, 0, sizeof(wss));
    }

    // Memory usage of this mapping.
    // Memory usage of this mapping.
    MemUsage usage;
    MemUsage usage;
    // Working set within this mapping.
    // Working set within this mapping.
+18 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@
namespace android {
namespace android {
namespace meminfo {
namespace meminfo {


using VmaCallback = std::function<void(const Vma&)>;

class ProcMemInfo final {
class ProcMemInfo final {
    // Per-process memory accounting
    // Per-process memory accounting
  public:
  public:
@@ -38,6 +40,18 @@ class ProcMemInfo final {
    const MemUsage& Usage();
    const MemUsage& Usage();
    const MemUsage& Wss();
    const MemUsage& Wss();


    // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
    // constant reference to the vma vector after the collection is done.
    //
    // Each 'struct Vma' is *fully* populated by this method (unlike SmapsOrRollup).
    const std::vector<Vma>& Smaps(const std::string& path = "");

    // This method reads /proc/<pid>/smaps and calls the callback() for each
    // vma or map that it finds. The map is converted to 'struct Vma' object which is then
    // passed to the callback.
    // Returns 'false' if the file is malformed.
    bool ForEachVma(const VmaCallback& callback);

    // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
    // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
    // Pss and Private memory usage in 'stats'.  In particular, the method only populates the fields
    // Pss and Private memory usage in 'stats'.  In particular, the method only populates the fields
    // of the MemUsage structure that are intended to be used by Android's periodic Pss collection.
    // of the MemUsage structure that are intended to be used by Android's periodic Pss collection.
@@ -49,7 +63,6 @@ class ProcMemInfo final {
    //   private_clean
    //   private_clean
    //   private_dirty
    //   private_dirty
    //   SwapPss
    //   SwapPss
    //
    // All other fields of MemUsage are zeroed.
    // All other fields of MemUsage are zeroed.
    bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const;
    bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const;


@@ -73,6 +86,10 @@ class ProcMemInfo final {
    std::vector<uint16_t> swap_offsets_;
    std::vector<uint16_t> swap_offsets_;
};
};


// Makes callback for each 'vma' or 'map' found in file provided. The file is expected to be in the
// same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed.
bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback);

// Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
// Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
// from a file. The file MUST be in the same format as /proc/<pid>/smaps
// from a file. The file MUST be in the same format as /proc/<pid>/smaps
// or /proc/<pid>/smaps_rollup
// or /proc/<pid>/smaps_rollup
+185 −0
Original line number Original line Diff line number Diff line
@@ -365,6 +365,191 @@ VmFlags: rd wr mr mw me ac
    EXPECT_EQ(stats.swap_pss, 70);
    EXPECT_EQ(stats.swap_pss, 70);
}
}


TEST(TestProcMemInfo, ForEachVmaFromFileTest) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
    ProcMemInfo proc_mem(pid);

    std::vector<Vma> vmas;
    auto collect_vmas = [&](const Vma& v) { vmas.push_back(v); };
    ASSERT_TRUE(ForEachVmaFromFile(path, collect_vmas));

    // Expect values to be equal to what we have in testdata1/smaps_short
    // Check for sizes first
    ASSERT_EQ(vmas[0].usage.vss, 32768);
    EXPECT_EQ(vmas[1].usage.vss, 11204);
    EXPECT_EQ(vmas[2].usage.vss, 16896);
    EXPECT_EQ(vmas[3].usage.vss, 260);
    EXPECT_EQ(vmas[4].usage.vss, 6060);
    EXPECT_EQ(vmas[5].usage.vss, 4);

    // Check for names
    EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
    EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
    EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
    EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
    EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
    EXPECT_EQ(vmas[5].name, "[vsyscall]");

    EXPECT_EQ(vmas[0].usage.rss, 2048);
    EXPECT_EQ(vmas[1].usage.rss, 11188);
    EXPECT_EQ(vmas[2].usage.rss, 15272);
    EXPECT_EQ(vmas[3].usage.rss, 260);
    EXPECT_EQ(vmas[4].usage.rss, 4132);
    EXPECT_EQ(vmas[5].usage.rss, 0);

    EXPECT_EQ(vmas[0].usage.pss, 113);
    EXPECT_EQ(vmas[1].usage.pss, 2200);
    EXPECT_EQ(vmas[2].usage.pss, 15272);
    EXPECT_EQ(vmas[3].usage.pss, 260);
    EXPECT_EQ(vmas[4].usage.pss, 1274);
    EXPECT_EQ(vmas[5].usage.pss, 0);

    EXPECT_EQ(vmas[0].usage.uss, 0);
    EXPECT_EQ(vmas[1].usage.uss, 1660);
    EXPECT_EQ(vmas[2].usage.uss, 15272);
    EXPECT_EQ(vmas[3].usage.uss, 260);
    EXPECT_EQ(vmas[4].usage.uss, 0);
    EXPECT_EQ(vmas[5].usage.uss, 0);

    EXPECT_EQ(vmas[0].usage.private_clean, 0);
    EXPECT_EQ(vmas[1].usage.private_clean, 0);
    EXPECT_EQ(vmas[2].usage.private_clean, 0);
    EXPECT_EQ(vmas[3].usage.private_clean, 260);
    EXPECT_EQ(vmas[4].usage.private_clean, 0);
    EXPECT_EQ(vmas[5].usage.private_clean, 0);

    EXPECT_EQ(vmas[0].usage.private_dirty, 0);
    EXPECT_EQ(vmas[1].usage.private_dirty, 1660);
    EXPECT_EQ(vmas[2].usage.private_dirty, 15272);
    EXPECT_EQ(vmas[3].usage.private_dirty, 0);
    EXPECT_EQ(vmas[4].usage.private_dirty, 0);
    EXPECT_EQ(vmas[5].usage.private_dirty, 0);

    EXPECT_EQ(vmas[0].usage.shared_clean, 0);
    EXPECT_EQ(vmas[1].usage.shared_clean, 80);
    EXPECT_EQ(vmas[2].usage.shared_clean, 0);
    EXPECT_EQ(vmas[3].usage.shared_clean, 0);
    EXPECT_EQ(vmas[4].usage.shared_clean, 4132);
    EXPECT_EQ(vmas[5].usage.shared_clean, 0);

    EXPECT_EQ(vmas[0].usage.shared_dirty, 2048);
    EXPECT_EQ(vmas[1].usage.shared_dirty, 9448);
    EXPECT_EQ(vmas[2].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[3].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[4].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[5].usage.shared_dirty, 0);

    EXPECT_EQ(vmas[0].usage.swap, 0);
    EXPECT_EQ(vmas[1].usage.swap, 0);
    EXPECT_EQ(vmas[2].usage.swap, 0);
    EXPECT_EQ(vmas[3].usage.swap, 0);
    EXPECT_EQ(vmas[4].usage.swap, 0);
    EXPECT_EQ(vmas[5].usage.swap, 0);

    EXPECT_EQ(vmas[0].usage.swap_pss, 0);
    EXPECT_EQ(vmas[1].usage.swap_pss, 0);
    EXPECT_EQ(vmas[2].usage.swap_pss, 0);
    EXPECT_EQ(vmas[3].usage.swap_pss, 0);
    EXPECT_EQ(vmas[4].usage.swap_pss, 0);
    EXPECT_EQ(vmas[5].usage.swap_pss, 0);
}

TEST(TestProcMemInfo, SmapsReturnTest) {
    ProcMemInfo proc_mem(pid);
    auto vmas = proc_mem.Smaps();
    EXPECT_FALSE(vmas.empty());
}

TEST(TestProcMemInfo, SmapsTest) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
    ProcMemInfo proc_mem(pid);
    auto vmas = proc_mem.Smaps(path);

    ASSERT_FALSE(vmas.empty());

    // Expect values to be equal to what we have in testdata1/smaps_short
    // Check for sizes first
    ASSERT_EQ(vmas[0].usage.vss, 32768);
    EXPECT_EQ(vmas[1].usage.vss, 11204);
    EXPECT_EQ(vmas[2].usage.vss, 16896);
    EXPECT_EQ(vmas[3].usage.vss, 260);
    EXPECT_EQ(vmas[4].usage.vss, 6060);
    EXPECT_EQ(vmas[5].usage.vss, 4);

    // Check for names
    EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
    EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
    EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
    EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
    EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
    EXPECT_EQ(vmas[5].name, "[vsyscall]");

    EXPECT_EQ(vmas[0].usage.rss, 2048);
    EXPECT_EQ(vmas[1].usage.rss, 11188);
    EXPECT_EQ(vmas[2].usage.rss, 15272);
    EXPECT_EQ(vmas[3].usage.rss, 260);
    EXPECT_EQ(vmas[4].usage.rss, 4132);
    EXPECT_EQ(vmas[5].usage.rss, 0);

    EXPECT_EQ(vmas[0].usage.pss, 113);
    EXPECT_EQ(vmas[1].usage.pss, 2200);
    EXPECT_EQ(vmas[2].usage.pss, 15272);
    EXPECT_EQ(vmas[3].usage.pss, 260);
    EXPECT_EQ(vmas[4].usage.pss, 1274);
    EXPECT_EQ(vmas[5].usage.pss, 0);

    EXPECT_EQ(vmas[0].usage.uss, 0);
    EXPECT_EQ(vmas[1].usage.uss, 1660);
    EXPECT_EQ(vmas[2].usage.uss, 15272);
    EXPECT_EQ(vmas[3].usage.uss, 260);
    EXPECT_EQ(vmas[4].usage.uss, 0);
    EXPECT_EQ(vmas[5].usage.uss, 0);

    EXPECT_EQ(vmas[0].usage.private_clean, 0);
    EXPECT_EQ(vmas[1].usage.private_clean, 0);
    EXPECT_EQ(vmas[2].usage.private_clean, 0);
    EXPECT_EQ(vmas[3].usage.private_clean, 260);
    EXPECT_EQ(vmas[4].usage.private_clean, 0);
    EXPECT_EQ(vmas[5].usage.private_clean, 0);

    EXPECT_EQ(vmas[0].usage.private_dirty, 0);
    EXPECT_EQ(vmas[1].usage.private_dirty, 1660);
    EXPECT_EQ(vmas[2].usage.private_dirty, 15272);
    EXPECT_EQ(vmas[3].usage.private_dirty, 0);
    EXPECT_EQ(vmas[4].usage.private_dirty, 0);
    EXPECT_EQ(vmas[5].usage.private_dirty, 0);

    EXPECT_EQ(vmas[0].usage.shared_clean, 0);
    EXPECT_EQ(vmas[1].usage.shared_clean, 80);
    EXPECT_EQ(vmas[2].usage.shared_clean, 0);
    EXPECT_EQ(vmas[3].usage.shared_clean, 0);
    EXPECT_EQ(vmas[4].usage.shared_clean, 4132);
    EXPECT_EQ(vmas[5].usage.shared_clean, 0);

    EXPECT_EQ(vmas[0].usage.shared_dirty, 2048);
    EXPECT_EQ(vmas[1].usage.shared_dirty, 9448);
    EXPECT_EQ(vmas[2].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[3].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[4].usage.shared_dirty, 0);
    EXPECT_EQ(vmas[5].usage.shared_dirty, 0);

    EXPECT_EQ(vmas[0].usage.swap, 0);
    EXPECT_EQ(vmas[1].usage.swap, 0);
    EXPECT_EQ(vmas[2].usage.swap, 0);
    EXPECT_EQ(vmas[3].usage.swap, 0);
    EXPECT_EQ(vmas[4].usage.swap, 0);
    EXPECT_EQ(vmas[5].usage.swap, 0);

    EXPECT_EQ(vmas[0].usage.swap_pss, 0);
    EXPECT_EQ(vmas[1].usage.swap_pss, 0);
    EXPECT_EQ(vmas[2].usage.swap_pss, 0);
    EXPECT_EQ(vmas[3].usage.swap_pss, 0);
    EXPECT_EQ(vmas[4].usage.swap_pss, 0);
    EXPECT_EQ(vmas[5].usage.swap_pss, 0);
}

TEST(ValidateProcMemInfoFlags, TestPageFlags1) {
TEST(ValidateProcMemInfoFlags, TestPageFlags1) {
    // Create proc object using libpagemap
    // Create proc object using libpagemap
    pm_kernel_t* ker;
    pm_kernel_t* ker;
+122 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,51 @@ static void add_mem_usage(MemUsage* to, const MemUsage& from) {
    to->shared_dirty += from.shared_dirty;
    to->shared_dirty += from.shared_dirty;
}
}


// Returns true if the line was valid smaps stats line false otherwise.
static bool parse_smaps_field(const char* line, MemUsage* stats) {
    char field[64];
    int len;
    if (sscanf(line, "%63s %n", field, &len) == 1 && *field && field[strlen(field) - 1] == ':') {
        const char* c = line + len;
        switch (field[0]) {
            case 'P':
                if (strncmp(field, "Pss:", 4) == 0) {
                    stats->pss = strtoull(c, nullptr, 10);
                } else if (strncmp(field, "Private_Clean:", 14) == 0) {
                    uint64_t prcl = strtoull(c, nullptr, 10);
                    stats->private_clean = prcl;
                    stats->uss += prcl;
                } else if (strncmp(field, "Private_Dirty:", 14) == 0) {
                    uint64_t prdi = strtoull(c, nullptr, 10);
                    stats->private_dirty = prdi;
                    stats->uss += prdi;
                }
                break;
            case 'S':
                if (strncmp(field, "Size:", 5) == 0) {
                    stats->vss = strtoull(c, nullptr, 10);
                } else if (strncmp(field, "Shared_Clean:", 13) == 0) {
                    stats->shared_clean = strtoull(c, nullptr, 10);
                } else if (strncmp(field, "Shared_Dirty:", 13) == 0) {
                    stats->shared_dirty = strtoull(c, nullptr, 10);
                } else if (strncmp(field, "Swap:", 5) == 0) {
                    stats->swap = strtoull(c, nullptr, 10);
                } else if (strncmp(field, "SwapPss:", 8) == 0) {
                    stats->swap_pss = strtoull(c, nullptr, 10);
                }
                break;
            case 'R':
                if (strncmp(field, "Rss:", 4) == 0) {
                    stats->rss = strtoull(c, nullptr, 10);
                }
                break;
        }
        return true;
    }

    return false;
}

bool ProcMemInfo::ResetWorkingSet(pid_t pid) {
bool ProcMemInfo::ResetWorkingSet(pid_t pid) {
    std::string clear_refs_path = ::android::base::StringPrintf("/proc/%d/clear_refs", pid);
    std::string clear_refs_path = ::android::base::StringPrintf("/proc/%d/clear_refs", pid);
    if (!::android::base::WriteStringToFile("1\n", clear_refs_path)) {
    if (!::android::base::WriteStringToFile("1\n", clear_refs_path)) {
@@ -75,6 +120,25 @@ const std::vector<Vma>& ProcMemInfo::Maps() {
    return maps_;
    return maps_;
}
}


const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
    if (!maps_.empty()) {
        return maps_;
    }

    auto collect_vmas = [&](const Vma& vma) { maps_.emplace_back(vma); };
    if (path.empty() && !ForEachVma(collect_vmas)) {
        LOG(ERROR) << "Failed to read smaps for Process " << pid_;
        maps_.clear();
    }

    if (!path.empty() && !ForEachVmaFromFile(path, collect_vmas)) {
        LOG(ERROR) << "Failed to read smaps from file " << path;
        maps_.clear();
    }

    return maps_;
}

const MemUsage& ProcMemInfo::Usage() {
const MemUsage& ProcMemInfo::Usage() {
    if (get_wss_) {
    if (get_wss_) {
        LOG(WARNING) << "Trying to read process memory usage for " << pid_
        LOG(WARNING) << "Trying to read process memory usage for " << pid_
@@ -103,6 +167,11 @@ const MemUsage& ProcMemInfo::Wss() {
    return wss_;
    return wss_;
}
}


bool ProcMemInfo::ForEachVma(const VmaCallback& callback) {
    std::string path = ::android::base::StringPrintf("/proc/%d/smaps", pid_);
    return ForEachVmaFromFile(path, callback);
}

bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const {
bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const {
    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
                                                     use_rollup ? "smaps_rollup" : "smaps");
                                                     use_rollup ? "smaps_rollup" : "smaps");
@@ -260,6 +329,59 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) {
}
}


// Public APIs
// Public APIs
bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) {
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    if (fp == nullptr) {
        return false;
    }

    char* line = nullptr;
    bool parsing_vma = false;
    ssize_t line_len;
    Vma vma;
    while ((line_len = getline(&line, 0, fp.get())) > 0) {
        // Make sure the line buffer terminates like a C string for ReadMapFile
        line[line_len] = '\0';

        if (parsing_vma) {
            if (parse_smaps_field(line, &vma.usage)) {
                // This was a stats field
                continue;
            }

            // Done collecting stats, make the call back
            callback(vma);
            parsing_vma = false;
        }

        vma.clear();
        // If it has, we are looking for the vma stats
        // 00400000-00409000 r-xp 00000000 fc:00 426998  /usr/lib/gvfs/gvfsd-http
        if (!::android::procinfo::ReadMapFileContent(
                    line, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
                              const char* name) {
                        vma.start = start;
                        vma.end = end;
                        vma.flags = flags;
                        vma.offset = pgoff;
                        vma.name = name;
                    })) {
            LOG(ERROR) << "Failed to parse " << path;
            return false;
        }
        parsing_vma = true;
    }

    // free getline() managed buffer
    free(line);

    if (parsing_vma) {
        callback(vma);
    }

    return true;
}

bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) {
bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) {
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    if (fp == nullptr) {
    if (fp == nullptr) {
+86 −0
Original line number Original line Diff line number Diff line
#! /system/bin/sh

TESTDATA_PATH=/data/nativetest64/libmeminfo_test/testdata1
SMAPS=$TESTDATA_PATH/smaps
OUT1=$TMPDIR/1.txt
OUT2=$TMPDIR/2.txt

showmap -f $SMAPS > $OUT1
showmap2 -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -f <smaps>";
else
    echo "pass: showmap -f <smaps>"
fi

showmap -q -f $SMAPS > $OUT1
showmap2 -q -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -q -f <smaps>";
else
    echo "pass: showmap -q -f <smaps>"
fi

showmap -v -f $SMAPS > $OUT1
showmap2 -v -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -v -f <smaps>";
else
    echo "pass: showmap -v -f <smaps>"
fi

showmap -a -f $SMAPS > $OUT1
showmap2 -a -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -a -f <smaps>";
else
    echo "pass: showmap -a -f <smaps>"
fi

# Note that all tests from here down that have the option
# '-a' added to the command are expected to fail as
# 'showmap2' actually fixes the 64-bit address truncating
# that was already happening with showmap
showmap -a -t -f $SMAPS > $OUT1
showmap2 -a -t -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -a -t -f <smaps>";
else
    echo "pass: showmap -a -t -f <smaps>"
fi

showmap -a -t -v -f $SMAPS > $OUT1
showmap2 -a -t -v -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -a -t -v -f <smaps>";
else
    echo "pass: showmap -a -t -v -f <smaps>"
fi

# Note: This test again is expected to fail as the new
# showmap fixes an issue with -t where the tool was only
# showing maps with private dirty pages. The '-t' option was however
# supposed to show all maps that have 'private' pages, clean or dirty.
showmap -t -f $SMAPS > $OUT1
showmap2 -t -f $SMAPS > $OUT2
diff $OUT1 $OUT2 > /dev/null
ret=$?
if [[ $ret != 0 ]]; then
    echo "fail: showmap -t -f <smaps>";
else
    echo "pass: showmap -t -f <smaps>"
fi

Loading