You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
9.6 KiB
469 lines
9.6 KiB
// Compares the number of operations with items in gheap-based algorithms
|
|
// to the number of operations with items in the corresponding STL algorithms.
|
|
//
|
|
// Pass -DNDEBUG for eliminating operations related to debugging checks.
|
|
|
|
#include "galgorithm.hpp"
|
|
#include "gheap.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <list>
|
|
#include <stdint.h> // for uintptr_t (<cstdint> is missing in C++03).
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
|
|
// Simulates a LRU list of pages, which can contain up to _max_lru_size entries.
|
|
// Each page's size is PAGE_MASK + 1 bytes.
|
|
struct lru
|
|
{
|
|
typedef list<uintptr_t> lru_t;
|
|
|
|
static const uintptr_t PAGE_MASK = (((uintptr_t)1) << 12) - 1;
|
|
|
|
// Maximum number of pages in LRU list.
|
|
static const size_t MAX_LRU_SIZE = 20;
|
|
|
|
// LRU list of pages. Front of the list contains least recently used pages.
|
|
static lru_t lru_pages;
|
|
|
|
// The number of simulated pagefaults since the last lru::init() call.
|
|
static int pagefaults;
|
|
|
|
// Resets the model to initial state.
|
|
static void reset()
|
|
{
|
|
lru_pages.clear();
|
|
pagefaults = 0;
|
|
}
|
|
|
|
// Simulates access to a memory pointed by ptr.
|
|
// Brings the accessed page to the back of LRU list.
|
|
// If the page is absent in LRU list, then increments pagefaults counter.
|
|
static void access_ptr(const void *const ptr)
|
|
{
|
|
assert(lru_pages.size() <= MAX_LRU_SIZE);
|
|
|
|
const uintptr_t page_num = ((uintptr_t)ptr) & ~PAGE_MASK;
|
|
lru_t::iterator it = find(lru_pages.begin(), lru_pages.end(),
|
|
page_num);
|
|
if (it == lru_pages.end()) {
|
|
const uintptr_t prev_page_num = page_num - PAGE_MASK - 1;
|
|
if (count(lru_pages.begin(), lru_pages.end(), prev_page_num) == 0) {
|
|
// Count pagefault only if the previous page is not in the LRU list.
|
|
// If the previous page is in the LRU list, then assume that the current
|
|
// page is already pre-fetched, so no hard pagefault.
|
|
++pagefaults;
|
|
}
|
|
|
|
lru_pages.push_front(page_num);
|
|
if (lru_pages.size() > MAX_LRU_SIZE) {
|
|
lru_pages.pop_back();
|
|
}
|
|
assert(lru_pages.size() <= MAX_LRU_SIZE);
|
|
}
|
|
else {
|
|
lru_pages.splice(lru_pages.begin(), lru_pages, it);
|
|
}
|
|
}
|
|
};
|
|
|
|
lru::lru_t lru::lru_pages;
|
|
int lru::pagefaults = 0;
|
|
|
|
|
|
struct A
|
|
{
|
|
static int default_ctors;
|
|
static int copy_ctors;
|
|
static int copy_assignments;
|
|
static int swaps;
|
|
static int cheap_dtors;
|
|
static int expensive_dtors;
|
|
static int move_ctors;
|
|
static int cheap_move_assignments;
|
|
static int expensive_move_assignments;
|
|
static int comparisons;
|
|
|
|
static void reset()
|
|
{
|
|
default_ctors = 0;
|
|
copy_ctors = 0;
|
|
copy_assignments = 0;
|
|
swaps = 0;
|
|
cheap_dtors = 0;
|
|
expensive_dtors = 0;
|
|
move_ctors = 0;
|
|
cheap_move_assignments = 0;
|
|
expensive_move_assignments = 0;
|
|
comparisons = 0;
|
|
lru::reset();
|
|
}
|
|
|
|
static void print()
|
|
{
|
|
cout << "default_ctors=" << default_ctors << ", copy_ctors=" <<
|
|
copy_ctors << ", copy_assignments=" << copy_assignments <<
|
|
", swaps=" << swaps << ", cheap_dtors=" << cheap_dtors <<
|
|
", expensive_dtors=" << expensive_dtors << ", move_ctors=" <<
|
|
move_ctors << ", cheap_move_assignments=" << cheap_move_assignments <<
|
|
", expensive_move_assignments=" << expensive_move_assignments <<
|
|
", comparisons=" << comparisons << ", pagefaults=" << lru::pagefaults <<
|
|
endl;
|
|
}
|
|
|
|
int value;
|
|
|
|
bool has_value() const
|
|
{
|
|
return (value >= 0);
|
|
}
|
|
|
|
int get_value() const
|
|
{
|
|
assert(has_value());
|
|
lru::access_ptr(this);
|
|
return value;
|
|
}
|
|
|
|
void set_value(const int v)
|
|
{
|
|
assert(v >= 0);
|
|
value = v;
|
|
lru::access_ptr(this);
|
|
}
|
|
|
|
void set_value(const A &a)
|
|
{
|
|
int v = a.get_value();
|
|
set_value(v);
|
|
}
|
|
|
|
void clear_value()
|
|
{
|
|
value = -1;
|
|
lru::access_ptr(this);
|
|
}
|
|
|
|
A()
|
|
{
|
|
++default_ctors;
|
|
clear_value();
|
|
}
|
|
|
|
A(const int v)
|
|
{
|
|
set_value(v);
|
|
}
|
|
|
|
A(const A &a)
|
|
{
|
|
++copy_ctors;
|
|
set_value(a);
|
|
}
|
|
|
|
void operator = (const A &a)
|
|
{
|
|
if (this == &a) {
|
|
return;
|
|
}
|
|
|
|
assert(has_value());
|
|
++copy_assignments;
|
|
set_value(a);
|
|
}
|
|
|
|
~A()
|
|
{
|
|
if (has_value()) {
|
|
++expensive_dtors;
|
|
}
|
|
else {
|
|
++cheap_dtors;
|
|
}
|
|
clear_value();
|
|
}
|
|
|
|
#ifdef GHEAP_CPP11
|
|
|
|
A(A &&a)
|
|
{
|
|
++move_ctors;
|
|
set_value(a);
|
|
a.clear_value();
|
|
}
|
|
|
|
void operator = (A &&a)
|
|
{
|
|
if (this == &a) {
|
|
return;
|
|
}
|
|
|
|
if (has_value()) {
|
|
++expensive_move_assignments;
|
|
}
|
|
else {
|
|
++cheap_move_assignments;
|
|
}
|
|
|
|
set_value(a);
|
|
a.clear_value();
|
|
}
|
|
|
|
#endif
|
|
};
|
|
|
|
int A::default_ctors;
|
|
int A::copy_ctors;
|
|
int A::copy_assignments;
|
|
int A::swaps;
|
|
int A::cheap_dtors;
|
|
int A::expensive_dtors;
|
|
int A::move_ctors;
|
|
int A::cheap_move_assignments;
|
|
int A::expensive_move_assignments;
|
|
int A::comparisons;
|
|
|
|
namespace std
|
|
{
|
|
template <>
|
|
void swap(A &a, A &b)
|
|
{
|
|
++A::swaps;
|
|
|
|
int tmp = a.get_value();
|
|
a.set_value(b);
|
|
b.set_value(tmp);
|
|
}
|
|
}
|
|
|
|
bool operator < (const A &a, const A &b)
|
|
{
|
|
++A::comparisons;
|
|
return (a.get_value() < b.get_value());
|
|
}
|
|
|
|
struct stl
|
|
{
|
|
static const char *name()
|
|
{
|
|
return "stl";
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void push_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
::std::push_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void pop_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
::std::pop_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void make_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
::std::make_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void sort_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
::std::sort_heap(first, last);
|
|
}
|
|
};
|
|
|
|
struct gtl
|
|
{
|
|
typedef gheap<> heap;
|
|
|
|
static const char *name()
|
|
{
|
|
return "gheap<>";
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void push_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
heap::push_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void pop_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
heap::pop_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void make_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
heap::make_heap(first, last);
|
|
}
|
|
|
|
template <class RandomAccessIterator>
|
|
static void sort_heap(const RandomAccessIterator &first,
|
|
const RandomAccessIterator &last)
|
|
{
|
|
heap::sort_heap(first, last);
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
|
|
void init_array(vector<A> &a, const size_t n)
|
|
{
|
|
a.clear();
|
|
srand(0);
|
|
generate_n(back_inserter(a), n, rand);
|
|
}
|
|
|
|
template <class Heap>
|
|
void test_push_heap(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_push_heap(" << Heap::name() << "): ";
|
|
|
|
init_array(a, n);
|
|
A::reset();
|
|
for (size_t i = 2; i <= n; ++i) {
|
|
Heap::push_heap(a.begin(), a.begin() + i);
|
|
}
|
|
A::print();
|
|
}
|
|
|
|
template <class Heap>
|
|
void test_pop_heap(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_pop_heap(" << Heap::name() << "): ";
|
|
|
|
init_array(a, n);
|
|
Heap::make_heap(a.begin(), a.end());
|
|
|
|
A::reset();
|
|
for (size_t i = 0; i < n - 1; ++i) {
|
|
Heap::pop_heap(a.begin(), a.end() - i);
|
|
}
|
|
A::print();
|
|
}
|
|
|
|
template <class Heap>
|
|
void test_make_heap(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_make_heap(" << Heap::name() << "): ";
|
|
|
|
init_array(a, n);
|
|
A::reset();
|
|
Heap::make_heap(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
template <class Heap>
|
|
void test_sort_heap(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_sort_heap(" << Heap::name() << "): ";
|
|
|
|
init_array(a, n);
|
|
Heap::make_heap(a.begin(), a.end());
|
|
|
|
A::reset();
|
|
Heap::sort_heap(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
void test_nway_mergesort_avg(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_nway_mergesort_avg(" << gtl::name() << "): ";
|
|
|
|
typedef galgorithm<gtl::heap> algorithm;
|
|
|
|
init_array(a, n);
|
|
A::reset();
|
|
algorithm::nway_mergesort(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
void test_nway_mergesort_worst(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_nway_mergesort_worst(" << gtl::name() << "): ";
|
|
|
|
typedef galgorithm<gtl::heap> algorithm;
|
|
|
|
// Simulate worst case for SGI STL sort implementation (aka introsort) -
|
|
// see http://en.wikipedia.org/wiki/Introsort .
|
|
// Actually n-way mergesort must be free of bad cases.
|
|
for (size_t i = 0; i < n; ++i) {
|
|
a[i] = n - i;
|
|
}
|
|
|
|
init_array(a, n);
|
|
A::reset();
|
|
algorithm::nway_mergesort(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
void test_sort_avg(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_sort_avg(" << stl::name() << "): ";
|
|
|
|
init_array(a, n);
|
|
A::reset();
|
|
sort(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
void test_sort_worst(vector<A> &a, const size_t n)
|
|
{
|
|
cout << " test_sort_worst(" << stl::name() << "): ";
|
|
|
|
// Simulate worst case for SGI STL sort implementation (aka introsort) -
|
|
// see http://en.wikipedia.org/wiki/Introsort .
|
|
for (size_t i = 0; i < n; ++i) {
|
|
a[i] = n - i;
|
|
}
|
|
|
|
A::reset();
|
|
sort(a.begin(), a.end());
|
|
A::print();
|
|
}
|
|
|
|
} // end of anonymous namespace
|
|
|
|
int main()
|
|
{
|
|
const size_t N = 1000000;
|
|
|
|
cout << "N=" << N << endl;
|
|
|
|
vector<A> a;
|
|
a.reserve(N);
|
|
|
|
test_push_heap<stl>(a, N);
|
|
test_push_heap<gtl>(a, N);
|
|
|
|
test_pop_heap<stl>(a, N);
|
|
test_pop_heap<gtl>(a, N);
|
|
|
|
test_make_heap<stl>(a, N);
|
|
test_make_heap<gtl>(a, N);
|
|
|
|
test_sort_heap<stl>(a, N);
|
|
test_sort_heap<gtl>(a, N);
|
|
|
|
test_nway_mergesort_avg(a, N);
|
|
test_nway_mergesort_worst(a, N);
|
|
test_sort_avg(a, N);
|
|
test_sort_worst(a, N);
|
|
}
|
|
|