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.
164 lines
2.5 KiB
164 lines
2.5 KiB
6 years ago
|
#pragma once
|
||
|
|
||
|
#include "compiler.h"
|
||
|
|
||
|
#include <err.h>
|
||
|
|
||
|
#include <atomic>
|
||
|
//#include <cassert>
|
||
|
#include <cstdint>
|
||
|
|
||
|
template<typename T>
|
||
|
class distribution
|
||
|
{
|
||
|
T min_, max_, sum_;
|
||
|
uint64_t count_;
|
||
|
|
||
|
public:
|
||
|
distribution() : min_(), max_(), sum_(), count_(0) { }
|
||
|
|
||
|
T add(T val)
|
||
|
{
|
||
|
if (val < min_ || count_ == 0)
|
||
|
min_ = val;
|
||
|
if (val > max_ || count_ == 0)
|
||
|
max_ = val;
|
||
|
sum_ += val;
|
||
|
count_ += 1;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
distribution &operator+=(const distribution &o)
|
||
|
{
|
||
|
if ((o.min_ < min_ || count_ == 0) && o.count_)
|
||
|
min_ = o.min_;
|
||
|
if ((o.max_ > max_ || count_ == 0) && o.count_)
|
||
|
max_ = o.max_;
|
||
|
sum_ += o.sum_;
|
||
|
count_ += o.count_;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
T sum() const
|
||
|
{
|
||
|
return sum_;
|
||
|
}
|
||
|
|
||
|
T min() const
|
||
|
{
|
||
|
return min_;
|
||
|
}
|
||
|
|
||
|
T max() const
|
||
|
{
|
||
|
return max_;
|
||
|
}
|
||
|
|
||
|
T span() const
|
||
|
{
|
||
|
return max() - min();
|
||
|
}
|
||
|
|
||
|
uint64_t count() const
|
||
|
{
|
||
|
return count_;
|
||
|
}
|
||
|
|
||
|
T mean() const
|
||
|
{
|
||
|
return sum() / count();
|
||
|
}
|
||
|
|
||
|
double meand() const
|
||
|
{
|
||
|
return sum() / (double)count();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename T>
|
||
|
class concurrent_distribution
|
||
|
{
|
||
|
// XXX Use a locked hash table from thread::id to distribution<T>
|
||
|
// and cache the per-thread distribution in a thread-local.
|
||
|
enum { MAX_THREADS = 100 };
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
distribution<T> dist __mpalign__;
|
||
|
__padout__;
|
||
|
} dists[MAX_THREADS];
|
||
|
mutable std::atomic<bool> dirty;
|
||
|
mutable distribution<T> combined;
|
||
|
|
||
|
static int getid()
|
||
|
{
|
||
|
static std::atomic<int> nextid;
|
||
|
static __thread int myid = -1;
|
||
|
if (myid == -1) {
|
||
|
myid = nextid++;
|
||
|
//assert(myid < MAX_THREADS);
|
||
|
if (myid >= MAX_THREADS || myid < 0)
|
||
|
errx(-1, "myid >= max threads %d\n", myid);
|
||
|
}
|
||
|
return myid;
|
||
|
}
|
||
|
|
||
|
distribution<T> &collect() const
|
||
|
{
|
||
|
if (dirty.load(std::memory_order_relaxed)) {
|
||
|
dirty = false;
|
||
|
|
||
|
combined = distribution<T>();
|
||
|
for (auto &d : dists)
|
||
|
combined += d.dist;
|
||
|
}
|
||
|
return combined;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
concurrent_distribution() : dirty(false) { }
|
||
|
|
||
|
T add(T val)
|
||
|
{
|
||
|
if (!dirty.load(std::memory_order_relaxed))
|
||
|
dirty.store(true, std::memory_order_relaxed);
|
||
|
dists[getid()].dist.add(val);
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
T sum() const
|
||
|
{
|
||
|
return collect().sum();
|
||
|
}
|
||
|
|
||
|
T min() const
|
||
|
{
|
||
|
return collect().min();
|
||
|
}
|
||
|
|
||
|
T max() const
|
||
|
{
|
||
|
return collect().max();
|
||
|
}
|
||
|
|
||
|
T span() const
|
||
|
{
|
||
|
return collect().span();
|
||
|
}
|
||
|
|
||
|
uint64_t count() const
|
||
|
{
|
||
|
return collect().count();
|
||
|
}
|
||
|
|
||
|
T mean() const
|
||
|
{
|
||
|
return collect().mean();
|
||
|
}
|
||
|
|
||
|
double meand() const
|
||
|
{
|
||
|
return collect().meand();
|
||
|
}
|
||
|
};
|