Add logging of CoreCLR/non-CoreCLR memory consumption parts (turned on with --show...
authorGleb Balykov <g.balykov@samsung.com>
Fri, 15 Sep 2017 19:04:42 +0000 (22:04 +0300)
committerRuben Ayrapetyan <r.ayrapetyan@samsung.com>
Fri, 15 Sep 2017 19:09:49 +0000 (22:09 +0300)
src/analyze/accumulatedtracedata.cpp
src/analyze/accumulatedtracedata.h
src/analyze/allocationdata.h
src/analyze/gui/gui.cpp
src/analyze/gui/mainwindow.cpp
src/analyze/gui/parser.cpp
src/analyze/gui/summarydata.h
src/track/heaptrack_preload.cpp
src/track/libheaptrack.cpp
src/track/libheaptrack.h

index f7746be..420ed89 100644 (file)
@@ -42,6 +42,7 @@ using namespace std;
 AllocationData::DisplayId AllocationData::display = AllocationData::DisplayId::malloc;
 
 bool AccumulatedTraceData::isHideUnmanagedStackParts = false;
+bool AccumulatedTraceData::isShowCoreCLRPartOption = false;
 
 namespace {
 
@@ -230,6 +231,13 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
             TraceNode node;
             reader >> node.ipIndex;
             reader >> node.parentIndex;
+
+            AllocationData::CoreCLRType coreclrType;
+            if (isShowCoreCLRPartOption)
+            {
+                coreclrType = checkIsNodeCoreCLR(node.ipIndex);
+            }
+
             // skip operator new and operator new[] at the beginning of traces
             while (find(opNewIpIndices.begin(), opNewIpIndices.end(), node.ipIndex) != opNewIpIndices.end()) {
                 node = findTrace(node.parentIndex);
@@ -248,6 +256,16 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
                 }
             }
 
+            if (isShowCoreCLRPartOption)
+            {
+                coreclrType = combineTwoTypes(checkIsNodeCoreCLR(node.ipIndex), coreclrType);
+                if (coreclrType != AllocationData::CoreCLRType::CoreCLR)
+                {
+                    coreclrType = combineTwoTypes(checkCallStackIsCoreCLR(node.parentIndex), coreclrType);
+                }
+                node.coreclrType = coreclrType;
+            }
+
             traces.push_back(node);
         } else if (reader.mode() == 'i') {
             if (pass != FirstPass) {
@@ -280,17 +298,12 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
             }
         } else if (reader.mode() == '*') {
             uint64_t length, ptr;
-            int prot, fd;
+            int prot, fd, isCoreclr;
             TraceIndex traceIndex;
 
-            if (AllocationData::display == AllocationData::DisplayId::malloc
-                || AllocationData::display == AllocationData::DisplayId::managed) {
-                // we don't need the mmap/munmap details information for malloc/managed statistics
-                continue;
-            }
-
             if (!(reader >> length)
                 || !(reader >> prot)
+                || !(reader >> isCoreclr)
                 || !(reader >> fd)
                 || !(reader >> traceIndex.index)
                 || !(reader >> ptr)) {
@@ -308,6 +321,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
 
             rangeInfo.setProt(prot);
             rangeInfo.setFd(fd);
+            rangeInfo.setIsCoreCLR(isCoreclr);
             rangeInfo.setTraceIndex(traceIndex.index);
 
             combineContiguousSimilarRanges();
@@ -322,12 +336,6 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
         } else if (reader.mode() == '/') {
             uint64_t length, ptr;
 
-            if (AllocationData::display == AllocationData::DisplayId::malloc
-                || AllocationData::display == AllocationData::DisplayId::managed) {
-                // we don't need the mmap/munmap details information for malloc/managed statistics
-                continue;
-            }
-
             if (!(reader >> length)
                 || !(reader >> ptr)) {
                 cerr << "failed to parse line: " << reader.line() << endl;
@@ -396,6 +404,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
 
                     if(!addressRangeInfo.isPhysicalMemoryConsumptionSet) {
                         cerr << "Unknown range: 0x" << std::hex << addressRangeInfo.start << " (0x" << addressRangeInfo.size << " bytes)" << std::dec << endl;
+                        continue;
                     }
 
                     totalCost.privateClean.allocated += addressRangeInfo.getPrivateClean();
@@ -453,6 +462,42 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
                         allocation.shared.allocated += addressRangeInfo.getShared();
                     }
                 }
+
+                if (isShowCoreCLRPartOption)
+                {
+                    if (pass == SecondPass && totalCost.privateClean.peak == lastPrivateCleanPeakCost && timeStamp == lastPrivateCleanPeakTime
+                        && AllocationData::display == AllocationData::DisplayId::privateClean)
+                    {
+                        partCoreclrMMAP.peak = 0;
+                        partNonCoreclrMMAP.peak = 0;
+                        partUnknownMMAP.peak = 0;
+                        partUntrackedMMAP.peak = 0;
+
+                        calculatePeak(AllocationData::DisplayId::privateClean);
+                    }
+
+                    if (pass == SecondPass && totalCost.privateDirty.peak == lastPrivateDirtyPeakCost && timeStamp == lastPrivateDirtyPeakTime
+                        && AllocationData::display == AllocationData::DisplayId::privateDirty)
+                    {
+                        partCoreclrMMAP.peak = 0;
+                        partNonCoreclrMMAP.peak = 0;
+                        partUnknownMMAP.peak = 0;
+                        partUntrackedMMAP.peak = 0;
+
+                        calculatePeak(AllocationData::DisplayId::privateDirty);
+                    }
+
+                    if (pass == SecondPass && totalCost.shared.peak == lastSharedPeakCost && timeStamp == lastSharedPeakTime
+                        && AllocationData::display == AllocationData::DisplayId::shared)
+                    {
+                        partCoreclrMMAP.peak = 0;
+                        partNonCoreclrMMAP.peak = 0;
+                        partUnknownMMAP.peak = 0;
+                        partUntrackedMMAP.peak = 0;
+
+                        calculatePeak(AllocationData::DisplayId::shared);
+                    }
+                }
             }
 
             handleTotalCostUpdate();
@@ -462,12 +507,6 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
                 continue;
             }
 
-            if (AllocationData::display == AllocationData::DisplayId::malloc
-                || AllocationData::display == AllocationData::DisplayId::managed) {
-                // we don't need the physical memory consumption details information for malloc/managed statistics
-                continue;
-            }
-
             uint64_t addr, diff, size, privateDirty, privateClean, sharedDirty, sharedClean;
             int prot;
 
@@ -750,9 +789,267 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass)
         handleTimeStamp(timeStamp, totalTime);
     }
 
+    if (isShowCoreCLRPartOption)
+    {
+        AllocationData::Stats totalCoreclr;
+        AllocationData::Stats totalNonCoreclr;
+        AllocationData::Stats totalUnknown;
+        AllocationData::Stats totalUntracked;
+
+        if (AllocationData::display == AllocationData::DisplayId::malloc)
+        {
+            for (auto it = allocations.begin(); it != allocations.end(); ++it)
+            {
+                if (!isValidTrace(it->traceIndex))
+                {
+                    totalUnknown += *(it->getDisplay ());
+                    continue;
+                }
+
+                AllocationData::CoreCLRType isCoreclr = findTrace(it->traceIndex).coreclrType;
+
+                if (isCoreclr == AllocationData::CoreCLRType::CoreCLR)
+                {
+                    totalCoreclr += *(it->getDisplay ());
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::nonCoreCLR)
+                {
+                    totalNonCoreclr += *(it->getDisplay ());
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::untracked)
+                {
+                    totalUntracked += *(it->getDisplay ());
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::unknown)
+                {
+                    totalUnknown += *(it->getDisplay ());
+                }
+            }
+
+            partCoreclr = totalCoreclr;
+            partNonCoreclr = totalNonCoreclr;
+            partUnknown = totalUnknown;
+            partUntracked = totalUntracked;
+        }
+        else if (AllocationData::display == AllocationData::DisplayId::privateDirty
+                 || AllocationData::display == AllocationData::DisplayId::privateClean
+                 || AllocationData::display == AllocationData::DisplayId::shared)
+        {
+            for (auto it = addressRangeInfos.begin(); it != addressRangeInfos.end(); ++it)
+            {
+                int64_t val = AllocationData::display == AllocationData::DisplayId::privateDirty
+                              ? it->second.getPrivateDirty()
+                              : AllocationData::display == AllocationData::DisplayId::privateClean
+                                ? it->second.getPrivateClean()
+                                : AllocationData::display == AllocationData::DisplayId::shared
+                                  ? it->second.getShared()
+                                  : 0;
+
+                if (!isValidTrace(it->second.traceIndex))
+                {
+                    totalUnknown.leaked += val;
+                    continue;
+                }
+
+                AllocationData::CoreCLRType coreclrType = AllocationData::CoreCLRType::unknown;
+                if (it->second.isCoreCLR == 0)
+                {
+                    coreclrType = AllocationData::CoreCLRType::nonCoreCLR;
+                }
+                else if (it->second.isCoreCLR == 1)
+                {
+                    coreclrType = AllocationData::CoreCLRType::CoreCLR;
+                }
+                else if (it->second.isCoreCLR == 2)
+                {
+                    coreclrType = AllocationData::CoreCLRType::untracked;
+                }
+                assert(coreclrType != AllocationData::CoreCLRType::unknown);
+
+                AllocationData::CoreCLRType isCoreclr = combineTwoTypes(findTrace(it->second.traceIndex).coreclrType, coreclrType);
+
+                if (isCoreclr == AllocationData::CoreCLRType::CoreCLR)
+                {
+                    totalCoreclr.leaked += val;
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::nonCoreCLR)
+                {
+                    totalNonCoreclr.leaked += val;
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::untracked)
+                {
+                    totalUntracked.leaked += val;
+                }
+                else if (isCoreclr == AllocationData::CoreCLRType::unknown)
+                {
+                    totalUnknown.leaked += val;
+                }
+            }
+
+            partCoreclrMMAP.leaked = totalCoreclr.leaked;
+            partNonCoreclrMMAP.leaked = totalNonCoreclr.leaked;
+            partUnknownMMAP.leaked = totalUnknown.leaked;
+            partUntrackedMMAP.leaked = totalUntracked.leaked;
+        }
+    }
+
     return true;
 }
 
+void
+AccumulatedTraceData::calculatePeak(AllocationData::DisplayId type)
+{
+    for (auto i = addressRangeInfos.begin (); i != addressRangeInfos.end(); ++i)
+    {
+        const AddressRangeInfo& addressRangeInfo = i->second;
+
+        int64_t peak = 0;
+        switch (type)
+        {
+            case AllocationData::DisplayId::privateDirty:
+            {
+                peak = addressRangeInfo.getPrivateDirty();
+                break;
+            }
+            case AllocationData::DisplayId::privateClean:
+            {
+                peak = addressRangeInfo.getPrivateClean();
+                break;
+            }
+            case AllocationData::DisplayId::shared:
+            {
+                peak = addressRangeInfo.getShared();
+                break;
+            }
+            default:
+            {
+                assert(0);
+            }
+        }
+
+        if(!addressRangeInfo.isPhysicalMemoryConsumptionSet) {
+            continue;
+        }
+
+        if (!isValidTrace(addressRangeInfo.traceIndex))
+        {
+            partUnknownMMAP.peak += peak;
+            continue;
+        }
+
+        AllocationData::CoreCLRType coreclrType = AllocationData::CoreCLRType::unknown;
+        if (addressRangeInfo.isCoreCLR == 0)
+        {
+            coreclrType = AllocationData::CoreCLRType::nonCoreCLR;
+        }
+        else if (addressRangeInfo.isCoreCLR == 1)
+        {
+            coreclrType = AllocationData::CoreCLRType::CoreCLR;
+        }
+        else if (addressRangeInfo.isCoreCLR == 2)
+        {
+            coreclrType = AllocationData::CoreCLRType::untracked;
+        }
+
+        AllocationData::CoreCLRType isCoreclr = combineTwoTypes(findTrace(addressRangeInfo.traceIndex).coreclrType, coreclrType);
+
+        if (isCoreclr == AllocationData::CoreCLRType::CoreCLR)
+        {
+            partCoreclrMMAP.peak += peak;
+        }
+        else if (isCoreclr == AllocationData::CoreCLRType::nonCoreCLR)
+        {
+            partNonCoreclrMMAP.peak += peak;
+        }
+        else if (isCoreclr == AllocationData::CoreCLRType::untracked)
+        {
+            partUntrackedMMAP.peak += peak;
+        }
+        else if (isCoreclr == AllocationData::CoreCLRType::unknown)
+        {
+            partUnknownMMAP.peak += peak;
+        }
+    }
+}
+
+AllocationData::CoreCLRType
+AccumulatedTraceData::checkIsNodeCoreCLR(IpIndex ipindex)
+{
+    InstructionPointer ip = findIp(ipindex);
+    AllocationData::CoreCLRType coreclrType = AllocationData::CoreCLRType::unknown;
+
+    for (auto iter = addressRangeInfos.begin(); iter != addressRangeInfos.end(); ++iter)
+    {
+        if (iter->second.start <= ip.instructionPointer && iter->second.start + iter->second.size > ip.instructionPointer)
+        {
+            if (iter->second.isCoreCLR == 0)
+            {
+                coreclrType = AllocationData::CoreCLRType::nonCoreCLR;
+            }
+            else if (iter->second.isCoreCLR == 1)
+            {
+                coreclrType = AllocationData::CoreCLRType::CoreCLR;
+            }
+            else if (iter->second.isCoreCLR == 2)
+            {
+                coreclrType = AllocationData::CoreCLRType::untracked;
+            }
+            break;
+        }
+    }
+    if (coreclrType == AllocationData::CoreCLRType::unknown)
+    {
+        // warning here, address is not found in ranges
+    }
+
+    return coreclrType;
+}
+
+AllocationData::CoreCLRType
+AccumulatedTraceData::combineTwoTypes(AllocationData::CoreCLRType a, AllocationData::CoreCLRType b)
+{
+    if (a == AllocationData::CoreCLRType::CoreCLR
+        || b == AllocationData::CoreCLRType::CoreCLR)
+    {
+        return AllocationData::CoreCLRType::CoreCLR;
+    }
+
+    if (a == AllocationData::CoreCLRType::untracked
+        || b == AllocationData::CoreCLRType::untracked)
+    {
+        return AllocationData::CoreCLRType::untracked;
+    }
+
+    if (a == AllocationData::CoreCLRType::nonCoreCLR
+        || b == AllocationData::CoreCLRType::nonCoreCLR)
+    {
+        return AllocationData::CoreCLRType::nonCoreCLR;
+    }
+
+    return AllocationData::CoreCLRType::unknown;
+}
+
+AllocationData::CoreCLRType
+AccumulatedTraceData::checkCallStackIsCoreCLR(TraceIndex index)
+{
+    AllocationData::CoreCLRType isCoreclr = AllocationData::CoreCLRType::unknown;
+
+    while (isValidTrace(index))
+    {
+        TraceNode node = findTrace(index);
+        index = node.parentIndex;
+
+        if (node.coreclrType == AllocationData::CoreCLRType::CoreCLR)
+        {
+            return node.coreclrType;
+        }
+
+        isCoreclr = combineTwoTypes(isCoreclr, node.coreclrType);
+    }
+
+    return isCoreclr;
+}
+
 namespace { // helpers for diffing
 
 template <typename IndexT, typename SortF>
@@ -1047,6 +1344,11 @@ TraceNode AccumulatedTraceData::findTrace(const TraceIndex traceIndex) const
     }
 }
 
+bool AccumulatedTraceData::isValidTrace(const TraceIndex traceIndex) const
+{
+    return !(!traceIndex || traceIndex.index > traces.size());
+}
+
 TraceNode AccumulatedTraceData::findPrevTrace(const TraceIndex traceIndex) const
 {
     TraceNode trace = findTrace(traceIndex);
index 8575049..399c71c 100644 (file)
@@ -78,6 +78,7 @@ struct TraceNode
 {
     IpIndex ipIndex;
     TraceIndex parentIndex;
+    AllocationData::CoreCLRType coreclrType;
 };
 
 struct Allocation : public AllocationData
@@ -106,7 +107,7 @@ struct AllocationInfo
 struct AddressRangeInfo
 {
     AddressRangeInfo(uint64_t vStart, uint64_t vSize)
-        : start(vStart), size(vSize), isProtSet(false), isPhysicalMemoryConsumptionSet(false), isFdSet(false)
+        : start(vStart), size(vSize), isProtSet(false), isPhysicalMemoryConsumptionSet(false), isFdSet(false), isCoreCLRSet (false)
     {
         assert(!traceIndex);
     }
@@ -123,10 +124,12 @@ struct AddressRangeInfo
 
     mutable int prot;
     mutable int fd;
+    mutable int isCoreCLR;
 
     mutable bool isProtSet;
     mutable bool isPhysicalMemoryConsumptionSet;
     mutable bool isFdSet;
+    mutable bool isCoreCLRSet;
 
     uint64_t getPrivateClean() const
     {
@@ -226,6 +229,12 @@ struct AddressRangeInfo
         isFdSet = true;
     }
 
+    void setIsCoreCLR(int flag)
+    {
+        isCoreCLR = flag;
+        isCoreCLRSet = true;
+    }
+
     void setPhysicalMemoryConsumption(uint64_t smapsRangeSize,
                                       uint64_t vPrivateDirty,
                                       uint64_t vPrivateClean,
@@ -330,6 +339,12 @@ struct AccumulatedTraceData
     void mapRemoveRanges(const uint64_t start, const uint64_t size);
     void combineContiguousSimilarRanges();
 
+    AllocationData::CoreCLRType checkCallStackIsCoreCLR(TraceIndex traceIndex);
+    bool isValidTrace(const TraceIndex traceIndex) const;
+    AllocationData::CoreCLRType checkIsNodeCoreCLR(IpIndex ipindex);
+    AllocationData::CoreCLRType combineTwoTypes(AllocationData::CoreCLRType a, AllocationData::CoreCLRType b);
+    void calculatePeak(AllocationData::DisplayId type);
+
     // indices of functions that should stop the backtrace, e.g. main or static
     // initialization
     std::vector<StringIndex> stopIndices;
@@ -343,6 +358,17 @@ struct AccumulatedTraceData
     AddressRangesMap addressRangeInfos;
 
     static bool isHideUnmanagedStackParts;
+    static bool isShowCoreCLRPartOption;
+
+    AllocationData::Stats partCoreclr;
+    AllocationData::Stats partNonCoreclr;
+    AllocationData::Stats partUnknown;
+    AllocationData::Stats partUntracked;
+
+    AllocationData::Stats partCoreclrMMAP;
+    AllocationData::Stats partNonCoreclrMMAP;
+    AllocationData::Stats partUnknownMMAP;
+    AllocationData::Stats partUntrackedMMAP;
 };
 
 #endif // ACCUMULATEDTRACEDATA_H
index 36438cb..117f21e 100644 (file)
@@ -33,6 +33,14 @@ struct AllocationData
         shared
     };
 
+    enum class CoreCLRType
+    {
+        unknown,
+        CoreCLR,
+        nonCoreCLR,
+        untracked
+    };
+
     AllocationData()
         : malloc(),
           managed(),
index a592280..25c7b63 100644 (file)
@@ -71,6 +71,9 @@ int main(int argc, char** argv)
     QCommandLineOption hideUnmanagedStackPartsOption(QStringLiteral("hide-unmanaged-stacks"), QStringLiteral("Hide unmanaged parts of call stacks"));
     parser.addOption(hideUnmanagedStackPartsOption);
 
+    QCommandLineOption showCoreCLRPartOption(QStringLiteral("show-coreclr"), QStringLiteral("Show CoreCLR/non-CoreCLR memory distribution"));
+    parser.addOption(showCoreCLRPartOption);
+
     parser.process(app);
     aboutData.processCommandLine(&parser);
 
@@ -80,6 +83,7 @@ int main(int argc, char** argv)
     bool isShowPrivateClean = parser.isSet(showPrivateCleanOption);
     bool isShowShared = parser.isSet(showSharedOption);
     bool isHideUnmanagedStackParts = parser.isSet(hideUnmanagedStackPartsOption);
+    bool isShowCoreCLRPartOption = parser.isSet(showCoreCLRPartOption);
 
     if ((isShowMalloc ? 1 : 0)
         + (isShowManaged ? 1 : 0)
@@ -110,6 +114,10 @@ int main(int argc, char** argv)
         AccumulatedTraceData::isHideUnmanagedStackParts = true;
     }
 
+    if (isShowCoreCLRPartOption) {
+        AccumulatedTraceData::isShowCoreCLRPartOption = true;
+    }
+
     auto createWindow = []() -> MainWindow* {
         auto window = new MainWindow;
         window->setAttribute(Qt::WA_DeleteOnClose);
index d2f1c28..4f7a862 100644 (file)
@@ -310,6 +310,56 @@ MainWindow::MainWindow(QWidget* parent)
                            format.formatByteSize(data.cost.allocated / totalTimeS, 1, KFormat::MetricBinaryDialect))
                    << "</dl></qt>";
         }
+        if (AccumulatedTraceData::isShowCoreCLRPartOption)
+        {
+            QTextStream stream(&textRight);
+
+            if (AllocationData::display == AllocationData::DisplayId::malloc)
+            {
+                stream << "<qt><dl>" << i18n("<dt><b>peak heap memory consumption</b>:</dt><dd>%1 "
+                                             "after %2s</dd>"
+                                             "</dt><dd>%3 (CoreCLR), %4 (non-CoreCLR), %5 (unknown)</dd>",
+                                             format.formatByteSize(data.cost.peak, 1, KFormat::JEDECBinaryDialect),
+                                             peakTimeS,
+                                             format.formatByteSize(data.CoreCLRPart.peak, 1, KFormat::JEDECBinaryDialect),
+                                             format.formatByteSize(data.nonCoreCLRPart.peak, 1, KFormat::JEDECBinaryDialect),
+                                             format.formatByteSize(data.unknownPart.peak, 1, KFormat::JEDECBinaryDialect))
+                       << i18n("<dt><b>peak RSS</b> (including heaptrack "
+                               "overhead):</dt><dd>%1</dd>",
+                               format.formatByteSize(data.peakRSS, 1, KFormat::JEDECBinaryDialect))
+                       << i18n("<dt><b>total memory leaked</b>:</dt><dd>%1</dd>"
+                               "</dt><dd>%2 (CoreCLR), %3 (non-CoreCLR), %4 (unknown)</dd>",
+                               format.formatByteSize(data.cost.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.CoreCLRPart.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.nonCoreCLRPart.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.unknownPart.leaked, 1, KFormat::JEDECBinaryDialect))
+                       << "</dl></qt>";
+            }
+            else
+            {
+                stream << "<qt><dl>" << i18n("<dt><b>peak heap memory consumption</b>:</dt><dd>%1 "
+                                             "after %2s</dd>"
+                                             "</dt><dd>%3 (CoreCLR), %4 (non-CoreCLR), %5 (sbrk heap), %6 (unknown)</dd>",
+                                             format.formatByteSize(data.cost.peak, 1, KFormat::JEDECBinaryDialect),
+                                             peakTimeS,
+                                             format.formatByteSize(data.CoreCLRPart.peak, 1, KFormat::JEDECBinaryDialect),
+                                             format.formatByteSize(data.nonCoreCLRPart.peak, 1, KFormat::JEDECBinaryDialect),
+                                             format.formatByteSize(data.untrackedPart.peak, 1, KFormat::JEDECBinaryDialect),
+                                             format.formatByteSize(data.unknownPart.peak, 1, KFormat::JEDECBinaryDialect))
+                       << i18n("<dt><b>peak RSS</b> (including heaptrack "
+                               "overhead):</dt><dd>%1</dd>",
+                               format.formatByteSize(data.peakRSS, 1, KFormat::JEDECBinaryDialect))
+                       << i18n("<dt><b>total memory leaked</b>:</dt><dd>%1</dd>"
+                               "</dt><dd>%2 (CoreCLR), %3 (non-CoreCLR), %4 (sbrk heap), %5 (unknown)</dd>",
+                               format.formatByteSize(data.cost.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.CoreCLRPart.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.nonCoreCLRPart.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.untrackedPart.leaked, 1, KFormat::JEDECBinaryDialect),
+                               format.formatByteSize(data.unknownPart.leaked, 1, KFormat::JEDECBinaryDialect))
+                       << "</dl></qt>";
+            }
+        }
+        else
         {
             QTextStream stream(&textRight);
             stream << "<qt><dl>" << i18n("<dt><b>peak heap memory consumption</b>:</dt><dd>%1 "
index 13a0cfd..c8993c5 100644 (file)
@@ -622,9 +622,30 @@ void Parser::parse(const QString& path, const QString& diffBase)
 
         data->updateStringCache();
 
+        AllocationData::Stats *partCoreclr;
+        AllocationData::Stats *partNonCoreclr;
+        AllocationData::Stats *partUntracked;
+        AllocationData::Stats *partUnknown;
+
+        if (AllocationData::display == AllocationData::DisplayId::malloc)
+        {
+            partCoreclr = &data->partCoreclr;
+            partNonCoreclr = &data->partNonCoreclr;
+            partUntracked = &data->partUntracked;
+            partUnknown = &data->partUnknown;
+        }
+        else
+        {
+            partCoreclr = &data->partCoreclrMMAP;
+            partNonCoreclr = &data->partNonCoreclrMMAP;
+            partUntracked = &data->partUntrackedMMAP;
+            partUnknown = &data->partUnknownMMAP;
+        }
+
         emit summaryAvailable({QString::fromStdString(data->debuggee), *data->totalCost.getDisplay(), data->totalTime, data->getPeakTime(),
                                data->peakRSS * 1024,
-                               data->systemInfo.pages * data->systemInfo.pageSize, data->fromAttached});
+                               data->systemInfo.pages * data->systemInfo.pageSize, data->fromAttached,
+                               *partCoreclr, *partNonCoreclr, *partUntracked, *partUnknown});
 
         emit progressMessageAvailable(i18n("merging allocations..."));
         // merge allocations before modifying the data again
index 0327e25..347fbde 100644 (file)
@@ -32,6 +32,11 @@ struct SummaryData
     int64_t peakRSS;
     int64_t totalSystemMemory;
     bool fromAttached;
+
+    AllocationData::Stats CoreCLRPart;
+    AllocationData::Stats nonCoreCLRPart;
+    AllocationData::Stats untrackedPart;
+    AllocationData::Stats unknownPart;
 };
 Q_DECLARE_METATYPE(SummaryData)
 
index f5acc89..177e01d 100644 (file)
@@ -50,17 +50,59 @@ namespace __gnu_cxx {
 __attribute__((weak)) extern void __freeres();
 }
 
+static int isCoreCLR(const char *filename)
+{
+    const char *localFilename = strrchr(filename,'/');
+    if (!localFilename)
+    {
+        localFilename = filename;
+    }
+    else
+    {
+        ++localFilename;
+    }
+
+    if (strcmp(localFilename, "libclrjit.so") == 0
+        || strcmp(localFilename, "libcoreclr.so") == 0
+        || strcmp(localFilename, "libcoreclrtraceptprovider.so") == 0
+        || strcmp(localFilename, "libdbgshim.so") == 0
+        || strcmp(localFilename, "libmscordaccore.so") == 0
+        || strcmp(localFilename, "libmscordbi.so") == 0
+        || strcmp(localFilename, "libprotojit.so") == 0
+        || strcmp(localFilename, "libsosplugin.so") == 0
+        || strcmp(localFilename, "libsos.so") == 0
+        || strcmp(localFilename, "libsuperpmi-shim-collector.so") == 0
+        || strcmp(localFilename, "libsuperpmi-shim-counter.so") == 0
+        || strcmp(localFilename, "libsuperpmi-shim-simple.so") == 0
+        || strcmp(localFilename, "System.Globalization.Native.so") == 0
+        || strcmp(localFilename, "System.IO.Compression.Native.so") == 0
+        || strcmp(localFilename, "System.Native.so") == 0
+        || strcmp(localFilename, "System.Net.Http.Native.so") == 0
+        || strcmp(localFilename, "System.Net.Security.Native.so") == 0
+        || strcmp(localFilename, "System.Security.Cryptography.Native.OpenSsl.so") == 0
+        || strcmp(localFilename, "System.Security.Cryptography.Native.so") == 0)
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
 static bool isExiting = false;
 
 static int dl_iterate_phdr_get_maps(struct dl_phdr_info* info, size_t /*size*/, void* data)
 {
-    auto maps = (map<void *, pair<size_t, int>> *) data;
+    auto maps = (map<void *, tuple<size_t, int, int>> *) data;
 
     const char* fileName = info->dlpi_name;
     if (!fileName || !fileName[0]) {
         fileName = "x";
     }
 
+    int isCoreclr = isCoreCLR(fileName);
+
     debugLog<VerboseOutput>("dl_iterate_phdr_get_maps: %s %zx", fileName, info->dlpi_addr);
 
     for (int i = 0; i < info->dlpi_phnum; i++) {
@@ -85,7 +127,7 @@ static int dl_iterate_phdr_get_maps(struct dl_phdr_info* info, size_t /*size*/,
                 prot |= PROT_EXEC;
 
             if (maps->find(addr) == maps->end()) {
-                maps->insert(make_pair(addr, make_pair(size, prot)));
+                maps->insert(make_pair(addr, make_tuple(size, prot, isCoreclr)));
             } else {
                 debugLog<VerboseOutput>("dl_iterate_phdr_get_maps: repeated section address %s %zx", fileName, info->dlpi_addr);
             }
@@ -221,11 +263,11 @@ void init()
                    nullptr, nullptr);
 
     {
-        map<void *, pair<size_t, int>> map;
+        map<void *, tuple<size_t, int, int>> map;
 
         dl_iterate_phdr(&dl_iterate_phdr_get_maps, &map);
 
-        vector<pair<void *, pair<size_t, int>>> newMmaps;
+        vector<pair<void *, tuple<size_t, int, int>>> newMmaps;
 
         for (const auto & section : map) {
             newMmaps.push_back(section);
@@ -425,7 +467,7 @@ void* dlopen(const char* filename, int flag) noexcept
         hooks::init();
     }
 
-    map<void *, pair<size_t, int>> map_before, map_after;
+    map<void *, tuple<size_t, int, int>> map_before, map_after;
 
     if (!RecursionGuard::isActive) {
         RecursionGuard guard;
@@ -445,7 +487,7 @@ void* dlopen(const char* filename, int flag) noexcept
         if(map_after.size() < map_before.size()) {
             debugLog<VerboseOutput>("dlopen: count of sections after dlopen is less than before: %p %s %x", ret, filename, flag);
         } else if (map_after.size() != map_before.size()) {
-            vector<pair<void *, pair<size_t, int>>> newMmaps;
+            vector<pair<void *, tuple<size_t, int, int>>> newMmaps;
 
             if (!RecursionGuard::isActive) {
                 RecursionGuard guard;
@@ -476,7 +518,7 @@ int dlclose(void* handle) noexcept
         hooks::init();
     }
 
-    map<void *, pair<size_t, int>> map_before, map_after;
+    map<void *, tuple<size_t, int, int>> map_before, map_after;
 
     if (!isExiting) {
         if (!RecursionGuard::isActive) {
@@ -506,7 +548,7 @@ int dlclose(void* handle) noexcept
 
                     for (const auto & section_before : map_before) {
                         if (map_after.find(section_before.first) == map_after.end()) {
-                            munmaps.push_back(make_pair(section_before.first, section_before.second.first));
+                            munmaps.push_back(make_pair(section_before.first, get<0>(section_before.second)));
                         }
                     }
                 }
index 22c4f02..71096be 100644 (file)
@@ -371,7 +371,7 @@ public:
                     Trace trace;
                     trace.fill((void *) sbrk);
 
-                    heaptrack.handleMmap((void *) begin, end - begin, PROT_READ | PROT_WRITE, -1, trace);
+                    heaptrack.handleMmap((void *) begin, end - begin, PROT_READ | PROT_WRITE, 2, -1, trace);
                 }
 
                 isHeap = false;
@@ -447,6 +447,7 @@ public:
     void handleMmap(void* ptr,
                     size_t length,
                     int prot,
+                    int isCoreclr,
                     int fd,
                     const Trace& trace)
     {
@@ -458,8 +459,8 @@ public:
 
         size_t alignedLength = ((length + k_pageSize - 1) / k_pageSize) * k_pageSize;
 
-        if (fprintf(s_data->out, "* %zx %x %x %x %" PRIxPTR "\n",
-                    alignedLength, prot, fd, index, reinterpret_cast<uintptr_t>(ptr)) < 0) {
+        if (fprintf(s_data->out, "* %zx %x %x %x %x %" PRIxPTR "\n",
+                    alignedLength, prot, isCoreclr, fd, index, reinterpret_cast<uintptr_t>(ptr)) < 0) {
             writeError();
             return;
         }
@@ -826,7 +827,7 @@ void heaptrack_stop()
 }
 
 __attribute__((noinline))
-void heaptrack_dlopen(const vector<pair<void *, pair<size_t, int>>> &newMmaps, bool isPreloaded, void *dlopenOriginal)
+void heaptrack_dlopen(const vector<pair<void *, tuple<size_t, int, int>>> &newMmaps, bool isPreloaded, void *dlopenOriginal)
 {
     if (!RecursionGuard::isActive) {
         RecursionGuard guard;
@@ -845,7 +846,7 @@ void heaptrack_dlopen(const vector<pair<void *, pair<size_t, int>>> &newMmaps, b
         HeapTrack heaptrack(guard);
 
         for (const auto &mmapRecord : newMmaps) {
-            heaptrack.handleMmap(mmapRecord.first, mmapRecord.second.first, mmapRecord.second.second, -2 /* FIXME: */, trace);
+            heaptrack.handleMmap(mmapRecord.first, get<0>(mmapRecord.second), get<1>(mmapRecord.second), get<2>(mmapRecord.second), -2 /* FIXME: */, trace);
         }
     }
 }
@@ -924,7 +925,7 @@ void heaptrack_mmap(void* ptr, size_t length, int prot, int flags, int fd, off64
         trace.fill(2);
 
         HeapTrack heaptrack(guard);
-        heaptrack.handleMmap(ptr, length, prot, fd, trace);
+        heaptrack.handleMmap(ptr, length, prot, 0, fd, trace);
     }
 }
 
index d7e15f7..8435910 100644 (file)
@@ -81,7 +81,7 @@ void heaptrack_init(const char* outputFileName, heaptrack_callback_t initCallbac
 
 void heaptrack_stop();
 
-void heaptrack_dlopen(const std::vector<std::pair<void *, std::pair<size_t, int>>> &newMmaps, bool isPreloaded, void *dlopenOriginal);
+void heaptrack_dlopen(const std::vector<std::pair<void *, std::tuple<size_t, int, int>>> &newMmaps, bool isPreloaded, void *dlopenOriginal);
 void heaptrack_dlclose(const std::vector<std::pair<void *, size_t>> &unmaps);
 
 void heaptrack_malloc(void* ptr, size_t size);