Skip to content

Commit ab4f984

Browse files
committed
Sharing stats for the sharing map
1 parent 42ccf02 commit ab4f984

File tree

2 files changed

+353
-0
lines changed

2 files changed

+353
-0
lines changed

src/util/sharing_map.h

+203
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,36 @@ 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+
class sharing_map_statst
313+
{
314+
public:
315+
std::size_t num_nodes = 0;
316+
std::size_t num_unique_nodes = 0;
317+
std::size_t num_leafs = 0;
318+
std::size_t num_unique_leafs = 0;
319+
};
320+
321+
template <class Iterator>
322+
static sharing_map_statst get_sharing_stats(
323+
Iterator begin,
324+
Iterator end,
325+
std::function<sharing_mapt &(const Iterator)> f =
326+
[](const Iterator it) -> sharing_mapt & { return *it; });
327+
328+
template <class Iterator>
329+
static sharing_map_statst get_sharing_stats_map(Iterator begin, Iterator end);
330+
294331
protected:
295332
// helpers
296333

@@ -317,6 +354,11 @@ class sharing_mapt
317354
void gather_all(const baset &n, const unsigned depth, delta_viewt &delta_view)
318355
const;
319356

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

@@ -386,6 +428,167 @@ ::iterate(
386428
while(!stack.empty());
387429
}
388430

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

0 commit comments

Comments
 (0)