#include "config.h"
#include "pointermap.h"
+#ifdef __GNUC__
+#define POTENTIALLY_UNUSED __attribute__ ((unused))
+#else
+#define POTENTIALLY_UNUSED
+#endif
+
using namespace std;
namespace {
return true;
}
+namespace {
+
+template<typename IndexT, typename SortF>
+vector<IndexT> sortedIndices(size_t numIndices, SortF sorter)
+{
+ vector<IndexT> indices;
+ indices.resize(numIndices);
+ for (size_t i = 0; i < numIndices; ++i) {
+ indices[i].index = (i + 1);
+ }
+ sort(indices.begin(), indices.end(), sorter);
+ return indices;
+}
+
+vector<StringIndex> remapStrings(vector<string>& lhs, const vector<string>& rhs)
+{
+ unordered_map<string, StringIndex> stringRemapping;
+ StringIndex stringIndex;
+ {
+ stringRemapping.reserve(lhs.size());
+ for (const auto& string : lhs) {
+ ++stringIndex.index;
+ stringRemapping.insert(make_pair(string, stringIndex));
+ }
+ }
+
+ vector<StringIndex> map;
+ {
+ map.reserve(rhs.size() + 1);
+ map.push_back({});
+ for (const auto& string : rhs) {
+ auto it = stringRemapping.find(string);
+ if (it == stringRemapping.end()) {
+ ++stringIndex.index;
+ lhs.push_back(string);
+ map.push_back(stringIndex);
+ } else {
+ map.push_back(it->second);
+ }
+ }
+ }
+ return map;
+}
+
+template<typename T>
+inline const T& identity(const T& t)
+{
+ return t;
+}
+
+template<typename IpMapper>
+int compareTraceIndices(const TraceIndex &lhs, const AccumulatedTraceData& lhsData,
+ const TraceIndex &rhs, const AccumulatedTraceData& rhsData,
+ IpMapper ipMapper)
+{
+ if (!lhs && !rhs) {
+ return 0;
+ } else if (lhs && !rhs) {
+ return 1;
+ } else if (rhs && !lhs) {
+ return -1;
+ } else if (&lhsData == &rhsData && lhs == rhs) {
+ // fast-path if both indices are equal and we compare the same data
+ return 0;
+ }
+
+ const auto& lhsTrace = lhsData.findTrace(lhs);
+ const auto& rhsTrace = rhsData.findTrace(rhs);
+
+ const int parentComparsion = compareTraceIndices(lhsTrace.parentIndex, lhsData, rhsTrace.parentIndex, rhsData, ipMapper);
+ if (parentComparsion != 0) {
+ return parentComparsion;
+ } // else fall-through to below, parents are equal
+
+ const auto& lhsIp = lhsData.findIp(lhsTrace.ipIndex);
+ const auto& rhsIp = ipMapper(rhsData.findIp(rhsTrace.ipIndex));
+ if (lhsIp.equalWithoutAddress(rhsIp)) {
+ return 0;
+ }
+ return lhsIp.compareWithoutAddress(rhsIp) ? -1 : 1;
+}
+
+POTENTIALLY_UNUSED void printTrace(const AccumulatedTraceData& data, TraceIndex index)
+{
+ do {
+ const auto trace = data.findTrace(index);
+ const auto& ip = data.findIp(trace.ipIndex);
+ cerr << index << " (" << trace.ipIndex << ", " << trace.parentIndex << ")"
+ << '\t' << data.stringify(ip.functionIndex)
+ << " in " << data.stringify(ip.moduleIndex)
+ << " at " << data.stringify(ip.fileIndex) << ':' << ip.line
+ << '\n';
+ index = trace.parentIndex;
+ } while (index);
+ cerr << "---\n";
+}
+}
+
+void AccumulatedTraceData::diff(const AccumulatedTraceData& base)
+{
+ totalCost -= base.totalCost;
+
+ // step 0: remap strings and ips
+ const auto& stringMap = remapStrings(strings, base.strings);
+ auto remapString = [&stringMap] (StringIndex& index) {
+ if (index) {
+ index.index = stringMap[index.index].index;
+ }
+ };
+ auto remapIp = [&remapString] (InstructionPointer ip) -> InstructionPointer {
+ remapString(ip.moduleIndex);
+ remapString(ip.functionIndex);
+ remapString(ip.fileIndex);
+ return ip;
+ };
+
+ // step 1: sort trace indices of allocations for efficient lookup
+ // step 2: while at it, also merge equal allocations
+ vector<TraceIndex> allocationTraceNodes;
+ allocationTraceNodes.reserve(allocations.size());
+ for (auto it = allocations.begin(); it != allocations.end();) {
+ const auto& allocation = *it;
+ auto sortedIt = lower_bound(allocationTraceNodes.begin(), allocationTraceNodes.end(), allocation.traceIndex,
+ [this] (const TraceIndex& lhs, const TraceIndex& rhs) -> bool {
+ return compareTraceIndices(lhs, *this,
+ rhs, *this,
+ identity<InstructionPointer>) < 0;
+ });
+ if (sortedIt == allocationTraceNodes.end()
+ || compareTraceIndices(allocation.traceIndex, *this, *sortedIt, *this, identity<InstructionPointer>) != 0)
+ {
+ allocationTraceNodes.insert(sortedIt, allocation.traceIndex);
+ ++it;
+ } else if (*sortedIt != allocation.traceIndex) {
+ findAllocation(*sortedIt) += allocation;
+ it = allocations.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // step 3: iterate over rhs data and find matching traces
+ // if no match is found, copy the data over
+
+ auto sortedIps = sortedIndices<IpIndex>(instructionPointers.size(),
+ [this] (const IpIndex &lhs, const IpIndex &rhs) {
+ return findIp(lhs).compareWithoutAddress(findIp(rhs));
+ });
+
+ auto remapIpIndex = [&sortedIps, this, &base, &remapIp] (IpIndex rhsIndex) -> IpIndex {
+ if (!rhsIndex) {
+ return rhsIndex;
+ }
+
+ const auto& rhsIp = base.findIp(rhsIndex);
+ const auto& lhsIp = remapIp(rhsIp);
+
+ auto it = lower_bound(sortedIps.begin(), sortedIps.end(), lhsIp,
+ [this] (const IpIndex &lhs, const InstructionPointer &rhs) {
+ return findIp(lhs).compareWithoutAddress(rhs);
+ });
+ if (it != sortedIps.end() && findIp(*it).equalWithoutAddress(lhsIp)) {
+ return *it;
+ }
+
+ instructionPointers.push_back(lhsIp);
+
+ IpIndex ret;
+ ret.index = instructionPointers.size();
+ sortedIps.insert(it, ret);
+
+ return ret;
+ };
+
+ function<TraceIndex (TraceIndex)> copyTrace = [this, &base, remapIpIndex, ©Trace] (TraceIndex rhsIndex) -> TraceIndex {
+ if (!rhsIndex) {
+ return rhsIndex;
+ }
+
+ // new location, add it
+ const auto& rhsTrace = base.findTrace(rhsIndex);
+
+ TraceNode node;
+ node.parentIndex = copyTrace(rhsTrace.parentIndex);
+ node.ipIndex = remapIpIndex(rhsTrace.ipIndex);
+
+ traces.push_back(node);
+ TraceIndex ret;
+ ret.index = traces.size();
+
+ return ret;
+ };
+
+ auto remapTrace = [&base, &allocationTraceNodes, this, remapIp, copyTrace] (TraceIndex rhsIndex) -> TraceIndex {
+ if (!rhsIndex) {
+ return rhsIndex;
+ }
+
+ auto it = lower_bound(allocationTraceNodes.begin(), allocationTraceNodes.end(), rhsIndex,
+ [&base, this, remapIp] (const TraceIndex& lhs, const TraceIndex& rhs) -> bool {
+ return compareTraceIndices(lhs, *this, rhs, base, remapIp) < 0;
+ });
+
+ if (it != allocationTraceNodes.end()
+ && compareTraceIndices(*it, *this, rhsIndex, base, remapIp) == 0)
+ {
+ return *it;
+ }
+
+ TraceIndex ret = copyTrace(rhsIndex);
+ allocationTraceNodes.insert(it, ret);
+ return ret;
+ };
+
+ for (const auto& rhsAllocation : base.allocations) {
+ const auto lhsTrace = remapTrace(rhsAllocation.traceIndex);
+ assert(base.findIp(base.findTrace(rhsAllocation.traceIndex).ipIndex).equalWithoutAddress(findIp(findTrace(lhsTrace).ipIndex)));
+ findAllocation(lhsTrace) -= rhsAllocation;
+ }
+
+ // step 4: remove allocations that don't show any differences
+ allocations.erase(remove_if(allocations.begin(), allocations.end(),
+ [] (const Allocation& allocation) -> bool {
+ return !allocation.allocated && !allocation.allocations && !allocation.leaked
+ && !allocation.peak && !allocation.temporary;
+ }), allocations.end());
+}
+
Allocation& AccumulatedTraceData::findAllocation(const TraceIndex traceIndex)
{
if (traceIndex < m_maxAllocationTraceIndex) {