Permalink
Browse files

Optimize interval display for many short intervals.

  • Loading branch information...
ajclinto committed Apr 9, 2013
1 parent c1e9678 commit f38ef4cfe086eab27c28aef3bf1f3805ace3ca7e
Showing with 237 additions and 140 deletions.
  1. +3 −1 DisplayLayout.C
  2. +57 −26 DisplayLayout.h
  3. +100 −67 IntervalMap.h
  4. +26 −5 Loader.C
  5. +2 −1 Loader.h
  6. +6 −1 MemoryState.C
  7. +10 −4 Window.C
  8. +33 −35 test/test.C
View
@@ -191,7 +191,8 @@ DisplayLayout::update(
{
uint64 start, end;
- mmapmap.getTotalInterval(start, end);
+ MMapMapReader reader(mmapmap);
+ reader.getTotalInterval(start, end);
start >>= state.getIgnoreBits();
end >>= state.getIgnoreBits();
@@ -538,6 +539,7 @@ DisplayLayout::fillImage(
const Source &src,
int64 coff, int64 roff) const
{
+ //StopWatch timer;
image.zero();
for (auto it = myBlocks.begin(); it != myBlocks.end(); ++it)
View
@@ -179,56 +179,87 @@ class IntervalSource {
struct Page {
Page() : mySize(0) {}
- Page(uint64 size, uint32 idx)
+ Page(uint64 size, bool exists)
: mySize(size)
- , myIdx(idx) {}
+ , myExists(exists) {}
uint64 size() const { return mySize; }
uint64 mySize;
- uint32 myIdx;
+ bool myExists;
};
+ // These are the values used by the fragment shader
static inline int getIndex(const MMapInfo &info, bool)
{ return info.myIdx; }
static inline int getIndex(const std::string &, bool selected)
{ return selected ? 2 : 1; }
Page getPage(uint64 addr, uint64 size, uint64 &off) const
{
- uint64 start, end;
- T info = myIntervals.findAfter(addr << myIgnoreBits, start, end);
- bool selected = mySelection == start;
+ IntervalMapReader<T> reader(myIntervals);
+ auto it = reader.findAfter(addr << myIgnoreBits);
- start >>= myIgnoreBits;
- end += (1 << myIgnoreBits) - 1;
- end >>= myIgnoreBits;
-
- // addr does not overlap the range - return an empty page
off = 0;
- if (end <= addr)
- return Page(size, 0);
- if (start > addr)
- return Page(start-addr, 0);
- off = addr - start;
- return Page(end-start, getIndex(info, selected));
+ // addr does not overlap the range - return an empty page
+ if (it == reader.end() || (it.start()>>myIgnoreBits) >= addr + size)
+ return Page(size, false);
+
+ myBuffer.assign(size, 0);
+
+ while ((it.start()>>myIgnoreBits) < addr + size)
+ {
+ const uint64 a = (1 << myIgnoreBits) - 1;
+ const bool selected = mySelection == it.start();
+ uint64 start = it.start() >> myIgnoreBits;
+ uint64 end = (it.end()+a) >> myIgnoreBits;
+
+ start = SYSmax(start, addr);
+
+ for (uint64 i = start-addr; i < SYSmin(end-addr, size); i++)
+ myBuffer[i] = getIndex(it.value(), selected);
+
+ ++it;
+ if (it == reader.end())
+ break;
+
+ // When zoomed out there may be many intervals overlapping a
+ // single pixel. Check if the next interval would end at the
+ // same address and if so perform another binary search to
+ // advance to the next pixel.
+ if (((it.end()+a)>>myIgnoreBits) == end)
+ {
+ it = reader.findAfter(end << myIgnoreBits);
+ if (it == reader.end())
+ break;
+ }
+ }
+
+ return Page(size, true);
}
- inline bool exists(const Page &page) const { return page.myIdx; }
+ inline bool exists(const Page &page) const { return page.myExists; }
- inline void setScanline(uint32 *scan, Page &page, uint64, int n) const
- { std::fill_n(scan, n, page.myIdx); }
+ inline void setScanline(uint32 *scan, Page &, uint64 off, int n) const
+ {
+ memcpy(scan, &myBuffer[off], n*sizeof(uint32));
+ }
inline void gatherScanline(uint32 *scan,
- Page &page, uint64,
- const int *, int n) const
- { std::fill_n(scan, n, page.myIdx); }
+ Page &, uint64 off,
+ const int *lut, int n) const
+ {
+ const uint32 *state = &myBuffer[off];
+ for (int i = 0; i < n; i++)
+ scan[i] = state[lut[i]];
+ }
private:
- const IntervalMap<T> &myIntervals;
- uint64 mySelection;
- int myIgnoreBits;
+ const IntervalMap<T> &myIntervals;
+ mutable std::vector<uint32> myBuffer;
+ uint64 mySelection;
+ int myIgnoreBits;
};
#endif
View
@@ -33,63 +33,69 @@
#include <assert.h>
#include <iostream>
+template <typename T> class IntervalMapReader;
+template <typename T> class IntervalMapWriter;
+
// This class stores a map of non-overlapping intervals [start, end). The
// manipulator methods ensure that the interval map is always
-// non-overlapping.
+// non-overlapping. Access is through IntervalMapReader and
+// IntervalMapWriter to guarantee thread-safety.
template <typename T>
class IntervalMap {
private:
+ friend class IntervalMapReader<T>;
+ friend class IntervalMapWriter<T>;
+
struct Entry {
uint64 start;
T obj;
};
typedef std::map<uint64, Entry> MapType;
-public:
- void insert(uint64 start, uint64 end, const T &val)
- {
- QMutexLocker lock(&myLock);
+ MapType myMap;
+ mutable QMutex myLock;
+};
- clearOverlappingIntervals(start, end);
+// This class locks access to the interval map, so scope it appropriately.
+// This allows multiple operations on the map within the same lock
+template <typename T>
+class IntervalMapReader {
+ typedef typename IntervalMap<T>::MapType MapType;
+public:
+ IntervalMapReader(const IntervalMap<T> &imap)
+ : myMap(imap.myMap)
+ , myLock(&imap.myLock) {}
- myMap[end].start = start;
- myMap[end].obj = val;
- }
+ size_t size() const { return myMap.size(); }
- void erase(uint64 start, uint64 end)
- {
- QMutexLocker lock(&myLock);
+ class iterator {
+ public:
+ iterator(typename MapType::const_iterator it) : myIt(it) {}
- clearOverlappingIntervals(start, end);
- }
+ uint64 start() const { return myIt->second.start; }
+ uint64 end() const { return myIt->first; }
+ const T &value() const { return myIt->second.obj; }
- // Apply the function to all intervals in [start, end). If any
- // intervals overlap the boundary values, they are split and the
- // function is applied only to the included values.
- template <typename Func>
- void apply(uint64 start, uint64 end, const Func func)
- {
- typename MapType::iterator first, last;
- getOverlappingIntervals(start, end, first, last);
+ iterator& operator++() { ++myIt; return *this; }
+ iterator operator++(int)
+ { iterator tmp(*this); operator++(); return tmp; }
- for (; first != last; ++first)
- func(first->second.obj);
- }
+ bool operator==(const iterator& rhs) {return myIt == rhs.myIt;}
+ bool operator!=(const iterator& rhs) {return myIt != rhs.myIt;}
- size_t size() const { return myMap.size(); }
+ private:
+ friend class IntervalMap<T>;
+ typename MapType::const_iterator myIt;
+ };
- //
- // Note that these methods return elements by value. This is to ensure
- // thread safety in the case where another thread erases or overwrites
- // an element after it has been queried by the display thread.
- //
+ iterator begin() const { return iterator(myMap.begin()); }
+ iterator end() const { return iterator(myMap.end()); }
// Finds the element above and below the query address, and returns the
// closer of the two.
- T findClosest(uint64 addr, uint64 &start, uint64 &end) const
+ iterator findClosest(uint64 addr) const
{
- QMutexLocker lock(&myLock);
auto hi = myMap.upper_bound(addr);
if (hi != myMap.end())
{
@@ -100,51 +106,31 @@ class IntervalMap {
dist2(hi, addr) > dist2(lo, addr))
hi = lo;
- start = hi->second.start;
- end = hi->first;
- return hi->second.obj;
+ return iterator(hi);
}
else if (myMap.size())
{
- auto lo = myMap.rbegin();
- start = lo->second.start;
- end = lo->first;
- return lo->second.obj;
+ auto lo = hi;
+ --lo;
+ return iterator(lo);
}
- start = end = 0;
- return T();
+ return iterator(hi);
}
// Returns the element whose interval contains addr if it exists -
// otherwise 0.
- T find(uint64 addr) const
+ iterator find(uint64 addr) const
{
- uint64 start, end;
- return find(addr, start, end);
- }
- T find(uint64 addr, uint64 &start, uint64 &end) const
- {
- T rval = findAfter(addr, start, end);
- return start > addr ? T() : rval;
+ iterator rval = findAfter(addr);
+ return (rval == end() || rval.start() > addr) ? end() : rval;
}
// Returns the first interval that starts after addr or the interval
// that contains addr.
- T findAfter(uint64 addr, uint64 &start, uint64 &end) const
+ iterator findAfter(uint64 addr) const
{
- QMutexLocker lock(&myLock);
- auto it = myMap.upper_bound(addr);
-
- if (it != myMap.end())
- {
- start = it->second.start;
- end = it->first;
- return it->second.obj;
- }
-
- start = end = 0;
- return T();
+ return iterator(myMap.upper_bound(addr));
}
// Return the entire interval covered by the map
@@ -182,6 +168,48 @@ class IntervalMap {
return 0;
}
+private:
+ const MapType &myMap;
+ QMutexLocker myLock;
+};
+
+// This class locks access to the interval map, so scope it appropriately.
+// This allows multiple operations on the map within the same lock
+template <typename T>
+class IntervalMapWriter : public IntervalMapReader<T> {
+ typedef typename IntervalMap<T>::MapType MapType;
+public:
+ IntervalMapWriter(IntervalMap<T> &imap)
+ : IntervalMapReader<T>(imap)
+ , myMap(imap.myMap) {}
+
+ void insert(uint64 start, uint64 end, const T &val)
+ {
+ clearOverlappingIntervals(start, end);
+
+ myMap[end].start = start;
+ myMap[end].obj = val;
+ }
+
+ void erase(uint64 start, uint64 end)
+ {
+ clearOverlappingIntervals(start, end);
+ }
+
+ // Apply the function to all intervals in [start, end). If any
+ // intervals overlap the boundary values, they are split and the
+ // function is applied only to the included values.
+ template <typename Func>
+ void apply(uint64 start, uint64 end, const Func func)
+ {
+ typename MapType::iterator first, last;
+ getOverlappingIntervals(start, end, first, last);
+
+ for (; first != last; ++first)
+ func(first->second.obj);
+ }
+
+private:
// Find all intervals that overlap [start, end). If any intervals
// overlapped these boundary values, split the intervals to eliminate
// overlap.
@@ -219,18 +247,23 @@ class IntervalMap {
}
private:
- MapType myMap;
- mutable QMutex myLock;
+ MapType &myMap;
};
-typedef IntervalMap<std::string> StackTraceMap;
+#define MAP_TYPE(NAME, TYPE) \
+ typedef IntervalMap<TYPE> NAME; \
+ typedef IntervalMapReader<TYPE> NAME##Reader; \
+ typedef IntervalMapWriter<TYPE> NAME##Writer;
struct MMapInfo {
std::string myStr;
int myIdx;
bool myMapped;
};
-typedef IntervalMap<MMapInfo> MMapMap;
+MAP_TYPE(StackTraceMap, std::string)
+MAP_TYPE(MMapMap, MMapInfo)
+
+#undef MAP_TYPE
#endif
Oops, something went wrong.

0 comments on commit f38ef4c

Please sign in to comment.