Skip to content

Commit 186897c

Browse files
committed
Sharing stats for the sharing map
1 parent 4438b43 commit 186897c

File tree

2 files changed

+352
-0
lines changed

2 files changed

+352
-0
lines changed

src/util/sharing_map.h

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ Author: Daniel Poetzl
4444
template <class keyT, class valueT, class hashT, class equalT> \
4545
CV typename sharing_mapt<keyT, valueT, hashT, equalT>::ST \
4646
sharing_mapt<keyT, valueT, hashT, equalT>
47+
48+
#define SHARING_MAPT3(T, CV, ST) \
49+
template <class keyT, class valueT, class hashT, class equalT> \
50+
template <class T> \
51+
CV typename sharing_mapt<keyT, valueT, hashT, equalT>::ST \
52+
sharing_mapt<keyT, valueT, hashT, equalT>
4753
// clang-format on
4854

4955
// Note: Due to a bug in Visual Studio we need to add an additional "const"
@@ -128,6 +134,7 @@ class sharing_mapt
128134
friend void sharing_map_copy_test();
129135
friend void sharing_map_collision_test();
130136
friend void sharing_map_view_test();
137+
friend void sharing_map_sharing_stats_test();
131138

132139
~sharing_mapt()
133140
{
@@ -291,6 +298,35 @@ class sharing_mapt
291298
delta_viewt &delta_view,
292299
const bool only_common = true) const;
293300

301+
/// Stats about sharing between several sharing map instances. An instance of
302+
/// this class is returned by the get_sharing_map_stats_* functions.
303+
///
304+
/// The num_nodes field gives the total number of nodes in the given maps.
305+
/// Nodes that are part of n of the maps are counted n times.
306+
///
307+
/// The num_unique_nodes field gives the number of unique nodes in the given
308+
/// maps. A node that is part of several of the maps is only counted once.
309+
///
310+
/// The num_leafs and num_unique_leafs fields are similar to the above but
311+
/// only leafs are counted.
312+
struct sharing_map_statst
313+
{
314+
std::size_t num_nodes = 0;
315+
std::size_t num_unique_nodes = 0;
316+
std::size_t num_leafs = 0;
317+
std::size_t num_unique_leafs = 0;
318+
};
319+
320+
template <class Iterator>
321+
static sharing_map_statst get_sharing_stats(
322+
Iterator begin,
323+
Iterator end,
324+
std::function<sharing_mapt &(const Iterator)> f =
325+
[](const Iterator it) -> sharing_mapt & { return *it; });
326+
327+
template <class Iterator>
328+
static sharing_map_statst get_sharing_stats_map(Iterator begin, Iterator end);
329+
294330
protected:
295331
// helpers
296332

@@ -317,6 +353,11 @@ class sharing_mapt
317353
void gather_all(const baset &n, const unsigned depth, delta_viewt &delta_view)
318354
const;
319355

356+
std::size_t count_unmarked_nodes(
357+
bool leafs_only,
358+
std::set<void *> &marked,
359+
bool mark = true) const;
360+
320361
// dummy element returned when no element was found
321362
static mapped_type dummy;
322363

@@ -386,6 +427,167 @@ ::iterate(
386427
while(!stack.empty());
387428
}
388429

430+
SHARING_MAPT(std::size_t)
431+
::count_unmarked_nodes(bool leafs_only, std::set<void *> &marked, bool mark)
432+
const
433+
{
434+
if(empty())
435+
return 0;
436+
437+
unsigned count = 0;
438+
439+
typedef std::pair<unsigned, const baset *> stack_itemt;
440+
441+
std::stack<stack_itemt> stack;
442+
stack.push({0, &map});
443+
444+
do
445+
{
446+
const stack_itemt &si = stack.top();
447+
448+
const unsigned depth = si.first;
449+
const baset *bp = si.second;
450+
451+
stack.pop();
452+
453+
// internal node or container node
454+
const innert *ip = static_cast<const innert *>(bp);
455+
const unsigned use_count = ip->data.use_count();
456+
void *raw_ptr = ip->data.get();
457+
458+
if(use_count >= 2)
459+
{
460+
if(marked.find(raw_ptr) != marked.end())
461+
{
462+
continue;
463+
}
464+
465+
if(mark)
466+
{
467+
marked.insert(raw_ptr);
468+
}
469+
}
470+
471+
if(!leafs_only)
472+
{
473+
count++;
474+
}
475+
476+
if(depth < steps) // internal
477+
{
478+
const to_mapt &m = ip->get_to_map();
479+
SM_ASSERT(!m.empty());
480+
481+
for(const auto &item : m)
482+
{
483+
const innert *i = &item.second;
484+
stack.push({depth + 1, i});
485+
}
486+
}
487+
else // container
488+
{
489+
SM_ASSERT(depth == steps);
490+
491+
const leaf_listt &ll = ip->get_container();
492+
SM_ASSERT(!ll.empty());
493+
494+
for(const auto &l : ll)
495+
{
496+
const unsigned use_count = l.data.use_count();
497+
void *raw_ptr = l.data.get();
498+
499+
if(use_count >= 2)
500+
{
501+
if(marked.find(raw_ptr) != marked.end())
502+
{
503+
continue;
504+
}
505+
506+
if(mark)
507+
{
508+
marked.insert(raw_ptr);
509+
}
510+
}
511+
512+
count++;
513+
}
514+
}
515+
} while(!stack.empty());
516+
517+
return count;
518+
}
519+
520+
/// Get sharing stats
521+
///
522+
/// Complexity:
523+
/// - Worst case: O(N * H * log(S))
524+
/// - Best case: O(N + H)
525+
///
526+
/// \param begin: begin iterator
527+
/// \param end: end iterator
528+
/// \param f: function applied to the iterator to get a sharing map
529+
/// \return: sharing stats
530+
SHARING_MAPT3(Iterator, , sharing_map_statst)
531+
::get_sharing_stats(
532+
Iterator begin,
533+
Iterator end,
534+
std::function<sharing_mapt &(const Iterator)> f)
535+
{
536+
std::set<void *> marked;
537+
sharing_map_statst sms;
538+
539+
// We do a separate pass over the tree for each statistic. This is not very
540+
// efficient but the function is intended only for diagnosis purposes anyways.
541+
542+
// number of nodes
543+
for(Iterator it = begin; it != end; it++)
544+
{
545+
sms.num_nodes += f(it).count_unmarked_nodes(false, marked, false);
546+
}
547+
548+
SM_ASSERT(marked.empty());
549+
550+
// number of unique nodes
551+
for(Iterator it = begin; it != end; it++)
552+
{
553+
sms.num_unique_nodes += f(it).count_unmarked_nodes(false, marked, true);
554+
}
555+
556+
marked.clear();
557+
558+
// number of leafs
559+
for(Iterator it = begin; it != end; it++)
560+
{
561+
sms.num_leafs += f(it).count_unmarked_nodes(true, marked, false);
562+
}
563+
564+
SM_ASSERT(marked.empty());
565+
566+
// number of unique leafs
567+
for(Iterator it = begin; it != end; it++)
568+
{
569+
sms.num_unique_leafs += f(it).count_unmarked_nodes(true, marked, true);
570+
}
571+
572+
return sms;
573+
}
574+
575+
/// Get sharing stats
576+
///
577+
/// Complexity:
578+
/// - Worst case: O(N * H * log(S))
579+
/// - Best case: O(N + H)
580+
///
581+
/// \param begin: begin iterator of a map
582+
/// \param end: end iterator of a map
583+
/// \return: sharing stats
584+
SHARING_MAPT3(Iterator, , sharing_map_statst)
585+
::get_sharing_stats_map(Iterator begin, Iterator end)
586+
{
587+
return get_sharing_stats<Iterator>(
588+
begin, end, [](const Iterator it) -> sharing_mapt & { return it->second; });
589+
}
590+
389591
/// Get a view of the elements in the map
390592
/// A view is a list of pairs with the components being const references to the
391593
/// keys and values in the map.

0 commit comments

Comments
 (0)