#pragma once
#ifndef __AUTO_STATISTICS__
#define __AUTO_STATISTICS__
#include "Definitions.h"
#include <mach/thread_act.h>
#include <assert.h>
namespace Auto {
template <class TimeDataSource> class Timer {
TimeDataSource _timeDataSource; volatile uint64_t _start; volatile int64_t _accumulated; char _description[8];
public:
Timer() : _start(0), _accumulated(0) {}
inline boolean_t timer_running() const { return _start != 0; }
void start() { assert(!timer_running()); _start = _timeDataSource.current_time(); }
void stop() { assert(timer_running()); add_time(_timeDataSource.microseconds_duration(_start, _timeDataSource.current_time())); _start = 0; }
void reset() { assert(!timer_running()); _accumulated = 0; }
void add_time(usword_t duration) { OSAtomicAdd64(duration, &_accumulated); }
void add_time(Timer &other) { OSAtomicAdd64(other.microseconds(), &_accumulated); }
int64_t microseconds() const { assert(!timer_running()); return _accumulated; }
int64_t elapsed_microseconds() {
int64_t start = _start;
return start != 0 ? _timeDataSource.microseconds_duration(start, _timeDataSource.current_time()) : 0;
}
const char *time_string() {
int64_t timeval = microseconds();
if (timeval < 999) {
snprintf(_description, sizeof(_description), "%4.3g us", (float)timeval);
} else if (timeval < 999999) {
snprintf(_description, sizeof(_description), "%4.3g ms", (float)timeval/1000);
} else {
snprintf(_description, sizeof(_description), "%4.3g s", (float)timeval/1000/1000);
}
return _description;
}
};
#if 0
class UserCPUTimeDataSource {
public:
inline uint64_t current_time(void) {
thread_basic_info_data_t myinfo;
unsigned int count = sizeof(myinfo);
thread_info(pthread_mach_thread_np(pthread_self()), THREAD_BASIC_INFO, (thread_info_t)&myinfo, &count);
return (int64_t)myinfo.user_time.seconds*1000000 + (int64_t)myinfo.user_time.microseconds;
}
inline uint64_t microseconds_duration(uint64_t start, uint64_t end) { return end - start; }
};
typedef Timer<UserCPUTimeDataSource> UserCPUTimer;
#endif
class WallClockTimeDataSource {
inline static mach_timebase_info_data_t &cached_timebase() {
static mach_timebase_info_data_t _timebase;
if (_timebase.denom == 0) {
mach_timebase_info(&_timebase);
_timebase.denom *= 1000; }
return _timebase;
}
public:
uint64_t current_time(void) { return mach_absolute_time(); }
inline uint64_t microseconds_duration(uint64_t start, uint64_t end) {
mach_timebase_info_data_t &timebase = cached_timebase();
return (end - start) * timebase.numer / timebase.denom;
}
WallClockTimeDataSource() { }
};
typedef Timer<WallClockTimeDataSource> WallClockTimer;
class CollectionTimer {
public:
typedef WallClockTimer TotalCollectionTimer;
typedef WallClockTimer ScanTimer;
private:
TotalCollectionTimer _total_time; ScanTimer _scan_timer; boolean_t _scan_timer_enabled;
public:
CollectionTimer() : _scan_timer_enabled(false) {}
inline TotalCollectionTimer &total_time() { return _total_time; }
inline ScanTimer &scan_timer() { assert(_scan_timer_enabled); return _scan_timer; }
inline void enable_scan_timer() { _scan_timer_enabled = true; }
inline boolean_t scan_timer_enabled() { return _scan_timer_enabled; }
};
class Statistics {
volatile uint64_t _count;
volatile uint64_t _size;
volatile uint64_t _blocks_scanned;
volatile uint64_t _bytes_scanned;
WallClockTimer _idle_timer; volatile int64_t _should_collect_interval_start;
#ifdef MEASURE_TLC_STATS
volatile uint64_t _local_allocations; volatile uint64_t _global_allocations; volatile uint64_t _escaped; volatile uint64_t _local_collected; volatile uint64_t _global_collected; volatile uint64_t _recycled; volatile uint64_t _global_freed; #endif
public:
Statistics() { bzero(this, sizeof(Statistics)); }
inline void reset_for_heap_collection() {
_blocks_scanned = 0;
_bytes_scanned = 0;
}
inline uint64_t count() const { return _count; }
inline uint64_t size() const { return _size; }
WallClockTimer &idle_timer() { return _idle_timer; }
inline uint64_t blocks_scanned() const { return _blocks_scanned; }
inline uint64_t bytes_scanned() const { return _bytes_scanned; }
inline volatile int64_t *last_should_collect_time() { return &_should_collect_interval_start;}
#ifdef MEASURE_TLC_STATS
inline void print_tlc_stats() { malloc_printf("allocations - local: %ld, global: %ld. Escaped: %ld. collected - local: %ld, global: %ld. Recovered - local: %ld, global: %ld\n", _local_allocations, _global_allocations, _escaped, _local_collected, _global_collected, _recycled, _global_freed); }
#endif
inline void add_count(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_count); }
inline void add_size(int64_t size) { OSAtomicAdd64(size, (volatile int64_t *)&_size); }
inline void add_blocks_scanned(int64_t count) { OSAtomicAdd64(count, (volatile int64_t *)&_blocks_scanned); }
inline void add_bytes_scanned(int64_t count) { OSAtomicAdd64(count, (volatile int64_t *)&_bytes_scanned); }
#ifdef MEASURE_TLC_STATS
inline void add_local_allocations(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_local_allocations); }
inline void add_global_allocations(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_global_allocations); }
inline void add_escaped(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_escaped); }
inline void add_local_collected(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_local_collected); }
inline void add_global_collected(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_global_collected); }
inline void add_recycled(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_recycled); }
inline void add_global_freed(int64_t n) { OSAtomicAdd64(n, (volatile int64_t *)&_global_freed); }
#endif
};
};
#endif // __AUTO_STATISTICS__