diff options
Diffstat (limited to 'extern/carve/lib/timing.cpp')
-rw-r--r-- | extern/carve/lib/timing.cpp | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/extern/carve/lib/timing.cpp b/extern/carve/lib/timing.cpp new file mode 100644 index 00000000000..a98796cd8a7 --- /dev/null +++ b/extern/carve/lib/timing.cpp @@ -0,0 +1,436 @@ +// Begin License: +// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com). +// All rights reserved. +// +// This file is part of the Carve CSG Library (http://carve-csg.com/) +// +// This file may be used under the terms of the GNU General Public +// License version 2.0 as published by the Free Software Foundation +// and appearing in the file LICENSE.GPL2 included in the packaging of +// this file. +// +// This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE. +// End: + + +#if CARVE_USE_TIMINGS + +#if defined(HAVE_CONFIG_H) +# include <carve_config.h> +#endif + +#include <carve/timing.hpp> + +#include <cstring> +#include <list> +#include <stack> +#include <vector> +#include <map> +#include <iostream> +#include <string> +#include <algorithm> + +#ifdef WIN32 +#include <windows.h> +#else +#include <time.h> +#include <sys/time.h> +#endif + +#ifndef CARVE_USE_GLOBAL_NEW_DELETE +#define CARVE_USE_GLOBAL_NEW_DELETE 0 +#endif + +namespace carve { + static uint64_t memoryCurr = 0; + static uint64_t memoryTotal = 0; + unsigned blkCntCurr[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + unsigned blkCntTotal[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + void addBlk(unsigned size) { + unsigned i = 0; + while (i < 31 && (1U<<i) < size) ++i; + blkCntCurr[i]++; + blkCntTotal[i]++; + } + void remBlk(unsigned size) { + unsigned i = 0; + while (i < 31 && (1<<i) < size) ++i; + blkCntCurr[i]--; + } +} + +// lets provide a global new and delete as well + +#if CARVE_USE_GLOBAL_NEW_DELETE + +#if defined(__APPLE__) + +#include <stdlib.h> +#include <malloc/malloc.h> + +void* carve_alloc(size_t size) { + void *p = malloc(size); + if (p == 0) throw std::bad_alloc(); // ANSI/ISO compliant behavior + + unsigned sz = malloc_size(p); + carve::memoryCurr += sz; + carve::memoryTotal += sz; + carve::addBlk(sz); + return p; +} + +void carve_free(void *p) { + unsigned sz = malloc_size(p); + carve::memoryCurr -= sz; + carve::remBlk(sz); + free(p); +} + +#else + +void* carve_alloc(size_t size) { + void *p = malloc(size + 4); + if (p == 0) throw std::bad_alloc(); // ANSI/ISO compliant behavior + + int *sizePtr = (int*)p; + *sizePtr = size; + ++sizePtr; + carve::memoryCurr += size; + carve::memoryTotal += size; + carve::addBlk(size); + return sizePtr; +} + +void carve_free(void *p) { + // our memory block is actually a size of an int behind this pointer. + int *sizePtr = (int*)p; + + --sizePtr; + + carve::memoryCurr -= *sizePtr; + int size = *sizePtr; + carve::remBlk(size); + free(sizePtr); +} + +#endif + + +void* operator new (size_t size) { + return carve_alloc(size); +} + +void* operator new[](size_t size) { + return carve_alloc(size); +} + + +void operator delete (void *p) { + carve_free(p); +} + +void operator delete[](void *p) { + carve_free(p); +} + +#endif + +namespace carve { + + + +#ifdef WIN32 + + typedef __int64 precise_time_t; + + precise_time_t g_frequency; + + void initTime() { + ::QueryPerformanceFrequency((LARGE_INTEGER*)&g_frequency); + } + + void getTime(precise_time_t &t) { + ::QueryPerformanceCounter((LARGE_INTEGER*)&t); + } + + double diffTime(precise_time_t from, precise_time_t to) { + return (double)(to - from) / (double)g_frequency; + } + +#else + + typedef double precise_time_t; + + void initTime() { + } + + void getTime(precise_time_t &t) { + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + tv.tv_usec / 1000000.0; + } + + double diffTime(precise_time_t from, precise_time_t to) { + return to - from; + } + +#endif + + struct Entry { + Entry(int _id) { + id = _id; + time = 0; + parent = NULL; + } + int id; + double time; + int64_t memoryDiff; + int64_t allocTotal; + int delta_blk_cnt_curr[32]; + int delta_blk_cnt_total[32]; + Entry *parent; + std::vector<Entry *> children; + }; + + struct Timer { + struct cmp { + bool operator()(const std::pair<int, double> &a, const std::pair<int, double> &b) const { + return b.second < a.second; + } + bool operator()(const Entry * const &a, const Entry * const &b) const { + return b->time < a->time; + } + }; + + Timer() { + initTime(); + } + + struct Snapshot { + precise_time_t time; + uint64_t memory_curr; + uint64_t memory_total; + unsigned blk_cnt_curr[32]; + unsigned blk_cnt_total[32]; + }; + + static void getSnapshot(Snapshot &snapshot) { + getTime(snapshot.time); + snapshot.memory_curr = carve::memoryCurr; + snapshot.memory_total = carve::memoryTotal; + std::memcpy(snapshot.blk_cnt_curr, carve::blkCntCurr, sizeof(carve::blkCntCurr)); + std::memcpy(snapshot.blk_cnt_total, carve::blkCntTotal, sizeof(carve::blkCntTotal)); + } + + static void compareSnapshot(const Snapshot &from, const Snapshot &to, Entry *entry) { + entry->time = diffTime(from.time, to.time); + entry->memoryDiff = to.memory_curr - from.memory_curr; + entry->allocTotal = to.memory_total - from.memory_total; + for (int i = 0; i < 32; i++) { + entry->delta_blk_cnt_curr[i] = to.blk_cnt_curr[i] - from.blk_cnt_curr[i]; + entry->delta_blk_cnt_total[i] = to.blk_cnt_total[i] - from.blk_cnt_total[i]; + } + } + + std::stack<std::pair<Entry*, Snapshot> > currentTimers; + + void startTiming(int id) { + entries.push_back(Entry(id)); + currentTimers.push(std::make_pair(&entries.back(), Snapshot())); + getSnapshot(currentTimers.top().second); + } + + double endTiming() { + Snapshot end; + getSnapshot(end); + + Entry *entry = currentTimers.top().first; + compareSnapshot(currentTimers.top().second, end, entry); + + currentTimers.pop(); + if (!currentTimers.empty()) { + entry->parent = currentTimers.top().first; + entry->parent->children.push_back(entry); + } else { + root_entries.push_back(entry); + } + //std::sort(entry->children.begin(), entry->children.end(), cmp()); + return entry->time; + } + + typedef std::list<Entry> EntryList; + EntryList entries; + std::vector<Entry *> root_entries; + + std::map<int, std::string> names; + + static std::string formatMemory(int64_t value) { + + std::ostringstream result; + + result << (value >= 0 ? "+" : "-"); + if (value < 0) { + value = -value; + } + + int power = 1; + while (value > pow(10.0, power)) { + power++; + } + + for (power--; power >= 0; power--) { + int64_t base = pow(10.0, power); + int64_t amount = value / base; + result << +#if defined(_MSC_VER) && _MSC_VER < 1300 + (long) +#endif + amount; + if (power > 0 && (power % 3) == 0) { + result << ","; + } + value -= amount * base; + } + + result << " bytes"; + + return result.str(); + } + + void printEntries(std::ostream &o, const std::vector<Entry *> &entries, const std::string &indent, double parent_time) { + if (parent_time <= 0.0) { + parent_time = 0.0; + for (size_t i = 0; i < entries.size(); ++i) { + parent_time += entries[i]->time; + } + } + double t_tot = 0.0; + for (size_t i = 0; i < entries.size(); ++i) { + const Entry *entry = entries[i]; + + std::ostringstream r; + r << indent; + std::string str = names[entry->id]; + if (str.empty()) { + r << "(" << entry->id << ")"; + } else { + r << str; + } + r << " "; + std::string pad(r.str().size(), ' '); + r << " - exectime: " << entry->time << "s (" << (entry->time * 100.0 / parent_time) << "%)" << std::endl; + if (entry->allocTotal || entry->memoryDiff) { + r << pad << " - alloc: " << formatMemory(entry->allocTotal) << " delta: " << formatMemory(entry->memoryDiff) << std::endl; + r << pad << " - alloc blks:"; + for (int i = 0; i < 32; i++) { if (entry->delta_blk_cnt_total[i]) r << ' ' << ((1 << (i - 1)) + 1) << '-' << (1 << i) << ':' << entry->delta_blk_cnt_total[i]; } + r << std::endl; + r << pad << " - delta blks:"; + for (int i = 0; i < 32; i++) { if (entry->delta_blk_cnt_curr[i]) r << ' ' << ((1 << (i - 1)) + 1) << '-' << (1 << i) << ':' << entry->delta_blk_cnt_curr[i]; } + r << std::endl; + } + o << r.str(); + t_tot += entry->time; + if (entry->children.size()) printEntries(o, entry->children, indent + " ", entry->time); + } + if (t_tot < parent_time) { + o << indent << "*** unaccounted: " << (parent_time - t_tot) << "s (" << (100.0 - t_tot * 100.0 / parent_time) << "%)" << std::endl; + } + } + + void print() { + std::map<int, double> totals; + std::cerr << "Timings: " << std::endl; + // print out all the entries. + + //std::sort(root_entries.begin(), root_entries.end(), cmp()); + + printEntries(std::cerr, root_entries, " ", -1.0); + + for (EntryList::const_iterator it = entries.begin(); it != entries.end(); ++it) { + totals[(*it).id] += (*it).time; + } + + std::cerr << std::endl; + std::cerr << "Totals: " << std::endl; + + std::vector<std::pair<int, double> > sorted_totals; + sorted_totals.reserve(totals.size()); + for (std::map<int,double>::iterator it = totals.begin(); it != totals.end(); ++it) { + sorted_totals.push_back(*it); + } + + std::sort(sorted_totals.begin(), sorted_totals.end(), cmp()); + + for (std::vector<std::pair<int,double> >::iterator it = sorted_totals.begin(); it != sorted_totals.end(); ++it) { + std::cerr << " "; + std::string str = names[it->first]; + if (str.empty()) { + std::cerr << "(" << it->first << ")"; + } else { + std::cerr << str; + } + std::cerr << " - " << it->second << "s " << std::endl; + } + } + void registerID(int id, const char *name) { + names[id] = name; + } + int registerID(const char *name) { + int id = names.size() + 1; + names[id] = name; + return id; + } + + }; + + Timer timer; + + + TimingBlock::TimingBlock(int id) { +#if CARVE_USE_TIMINGS + timer.startTiming(id); +#endif + } + + TimingBlock::TimingBlock(const TimingName &name) { +#if CARVE_USE_TIMINGS + timer.startTiming(name.id); +#endif + } + + + TimingBlock::~TimingBlock() { +#if CARVE_USE_TIMINGS + timer.endTiming(); +#endif + } + void Timing::start(int id) { +#if CARVE_USE_TIMINGS + timer.startTiming(id); +#endif + } + + double Timing::stop() { +#if CARVE_USE_TIMINGS + return timer.endTiming(); +#endif + } + + void Timing::printTimings() { + timer.print(); + } + + void Timing::registerID(int id, const char *name) { + timer.registerID(id, name); + } + + TimingName::TimingName(const char *name) { + id = timer.registerID(name); + } + +} + +#endif |