summaryrefslogtreecommitdiff
path: root/extra/yassl/taocrypt/test/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extra/yassl/taocrypt/test/memory.cpp')
-rw-r--r--extra/yassl/taocrypt/test/memory.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/extra/yassl/taocrypt/test/memory.cpp b/extra/yassl/taocrypt/test/memory.cpp
new file mode 100644
index 00000000000..726c9c0ef54
--- /dev/null
+++ b/extra/yassl/taocrypt/test/memory.cpp
@@ -0,0 +1,312 @@
+// memory.cpp
+#include "../../include/lock.hpp" // locking
+#include <new> // std::bad_alloc
+#include <cstdlib> // malloc
+#include <cstring> // memset
+#include <fstream> // ofstream
+#include <sstream> // stringstream
+#include <cassert> // assert
+#include <iomanip> // setiosflags
+
+/*********************************************************************
+
+To use MemoryTracker merely add this file to your project
+No need to instantiate anything
+
+If your app is multi threaded define MULTI_THREADED
+
+*********************************************************************/
+
+
+// locals
+namespace {
+
+class MemoryTracker {
+ std::ofstream log_;
+public:
+ MemoryTracker();
+ ~MemoryTracker();
+private:
+ MemoryTracker(const MemoryTracker&); // hide copy
+ MemoryTracker& operator=(const MemoryTracker&); // and assign
+
+ void LogStats();
+};
+
+
+struct alloc_node {
+ alloc_node* left_;
+ alloc_node* right_;
+
+ alloc_node() : left_(0), right_(0) {}
+};
+
+
+alloc_node* Root = 0;
+
+size_t Allocs = 0;
+size_t DeAllocs = 0;
+size_t Bytes = 0;
+
+
+struct size_tracker {
+ size_t size_;
+ size_t count_;
+};
+
+size_tracker sizes[] =
+{
+ {0,0},
+ {2,0},
+ {4,0},
+ {8,0},
+ {16,0},
+ {32,0},
+ {64,0},
+ {128,0},
+ {256,0},
+ {512,0},
+ {1024,0},
+ {2048,0},
+ {4096,0},
+ {8192,0},
+};
+
+const size_t size_elements(sizeof(sizes) / sizeof(size_tracker));
+
+bool Tracking(false);
+
+using yaSSL::Mutex;
+typedef Mutex::Lock Lock;
+
+Mutex mutex;
+
+MemoryTracker theTracker;
+
+
+bool lookup(alloc_node*& find, void* key, alloc_node*& prev)
+{
+ bool found(false);
+
+ while (find) {
+ if (find == key) {
+ found = true;
+ break;
+ }
+ prev = find;
+ if (key < find)
+ find = find->left_;
+ else
+ find = find->right_;
+ }
+ return found;
+}
+
+
+// iterative insert
+void insert(alloc_node* entry)
+{
+ if (!Root) {
+ Root = entry;
+ return;
+ }
+
+ alloc_node* tmp = Root;
+ alloc_node* prev = 0;
+
+ if (lookup(tmp, entry, prev))
+ assert(0); // duplicate
+
+ if (entry < prev)
+ prev->left_ = entry;
+ else
+ prev->right_ = entry;
+}
+
+
+alloc_node* predecessorSwap(alloc_node* del)
+{
+ alloc_node* pred = del->left_;
+ alloc_node* predPrev = del;
+
+ while (pred->right_) {
+ predPrev = pred;
+ pred = pred->right_;
+ }
+ if (predPrev == del)
+ predPrev->left_ = pred->left_;
+ else
+ predPrev->right_ = pred->left_;
+
+ pred->left_ = del->left_;
+ pred->right_ = del->right_;
+
+ return pred;
+}
+
+
+// iterative remove
+void remove(void* ptr)
+{
+ alloc_node* del = Root;
+ alloc_node* prev = 0;
+ alloc_node* replace = 0;
+
+ if ( lookup(del, ptr, prev) == false)
+ assert(0); // oops, not there
+
+ if (del->left_ && del->right_) // two children
+ replace = predecessorSwap(del);
+ else if (!del->left_ && !del->right_) // no children
+ replace = 0;
+ else // one child
+ replace = (del->left_) ? del->left_ : del->right_;
+
+ if (del == Root)
+ Root = replace;
+ else if (prev->left_ == del)
+ prev->left_ = replace;
+ else
+ prev->right_ = replace;
+}
+
+
+typedef void (*fp)(alloc_node*, void*);
+
+void applyInOrder(alloc_node* root, fp f, void* arg)
+{
+ if (root == 0)
+ return;
+
+ applyInOrder(root->left_, f, arg);
+ f(root, arg);
+ applyInOrder(root->right_, f, arg);
+}
+
+
+void show(alloc_node* ptr, void* arg)
+{
+ std::ofstream* log = static_cast<std::ofstream*>(arg);
+ *log << ptr << '\n';
+}
+
+
+MemoryTracker::MemoryTracker() : log_("memory.log")
+{
+#ifdef __GNUC__
+ // Force pool allocator to cleanup at exit
+ setenv("GLIBCPP_FORCE_NEW", "1", 0);
+#endif
+
+#ifdef _MSC_VER
+ // msvc6 needs to create Facility for ostream before main starts, otherwise
+ // if another ostream is created and destroyed in main scope, log stats
+ // will access a dead Facility reference (std::numput)
+ int msvcFac = 6;
+ log_ << "MSVC " << msvcFac << "workaround" << std::endl;
+#endif
+
+
+ Tracking = true;
+}
+
+
+MemoryTracker::~MemoryTracker()
+{
+ // stop tracking before log (which will alloc on output)
+ Tracking = false;
+ LogStats();
+
+ //assert(Allocs == DeAllocs);
+ //assert(Root == 0);
+}
+
+
+void MemoryTracker::LogStats()
+{
+ log_ << "Number of Allocs: " << Allocs << '\n';
+ log_ << "Number of DeAllocs: " << DeAllocs << '\n';
+ log_ << "Number of bytes used: " << Bytes << '\n';
+
+ log_ << "Alloc size table:\n";
+ log_ << " Bytes " << '\t' << " Times\n";
+
+ for (size_t i = 0; i < size_elements; ++i) {
+ log_ << " " << sizes[i].size_ << " " << '\t';
+ log_ << std::setiosflags(std::ios::right) << std::setw(8);
+ log_ << sizes[i].count_ << '\n';
+ }
+
+ if (Allocs != DeAllocs) {
+ log_<< "Showing new'd allocs with no deletes" << '\n';
+ applyInOrder(Root, show, &log_);
+ }
+ log_.flush();
+}
+
+
+// return power of 2 up to size_tracker elements
+size_t powerOf2(size_t sz)
+{
+ size_t shifts = 0;
+
+ if (sz)
+ sz -= 1;
+ else
+ return 0;
+
+ while (sz) {
+ sz >>= 1;
+ ++shifts;
+ }
+
+ return shifts < size_elements ? shifts : size_elements;
+}
+
+
+} // namespace local
+
+
+void* operator new(size_t sz)
+{
+ // put alloc node in front of requested memory
+ void* ptr = malloc(sz + sizeof(alloc_node));
+ if (ptr) {
+ if (Tracking) {
+ Lock l(mutex);
+ ++Allocs;
+ Bytes += sz;
+ ++sizes[powerOf2(sz)].count_;
+ insert(new (ptr) alloc_node);
+ }
+ return static_cast<char*>(ptr) + sizeof(alloc_node);
+ }
+ else
+ assert(0);
+}
+
+
+void operator delete(void* ptr)
+{
+ if (ptr) {
+ ptr = static_cast<char*>(ptr) - sizeof(alloc_node); // correct offset
+ if (Tracking) {
+ Lock l(mutex);
+ ++DeAllocs;
+ remove(ptr);
+ }
+ free(ptr);
+ }
+}
+
+
+void* operator new[](size_t sz)
+{
+ return ::operator new(sz);
+}
+
+
+void operator delete[](void* ptr)
+{
+ ::operator delete(ptr);
+}