2021-02-10 19:06:27 +00:00
|
|
|
// modified from mutilate
|
|
|
|
// -*- c++ -*-
|
|
|
|
|
|
|
|
// 1. implement "fixed" generator
|
|
|
|
// 2. implement discrete generator
|
|
|
|
// 3. implement combine generator?
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2022-11-01 10:01:23 +00:00
|
|
|
#include <sys/_pthreadtypes.h>
|
2022-06-22 15:40:48 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
|
|
|
|
#include "defs.hh"
|
|
|
|
|
2021-02-10 19:06:27 +00:00
|
|
|
#define D(fmt, ...)
|
|
|
|
#define DIE(fmt, ...) (void)0;
|
|
|
|
|
|
|
|
#define FNV_64_PRIME (0x100000001b3ULL)
|
|
|
|
#define FNV1_64_INIT (0xcbf29ce484222325ULL)
|
|
|
|
static inline uint64_t
|
|
|
|
fnv_64_buf(const void *buf, size_t len)
|
|
|
|
{
|
|
|
|
uint64_t hval = FNV1_64_INIT;
|
|
|
|
|
|
|
|
unsigned char *bp = (unsigned char *)buf; /* start of buffer */
|
|
|
|
unsigned char *be = bp + len; /* beyond end of buffer */
|
|
|
|
|
|
|
|
while (bp < be) {
|
|
|
|
hval ^= (uint64_t)*bp++;
|
|
|
|
hval *= FNV_64_PRIME;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint64_t
|
|
|
|
fnv_64(uint64_t in)
|
|
|
|
{
|
|
|
|
return fnv_64_buf(&in, sizeof(in));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generator syntax:
|
|
|
|
//
|
|
|
|
// \d+ == fixed
|
|
|
|
// n[ormal]:mean,sd
|
|
|
|
// e[xponential]:lambda
|
|
|
|
// p[areto]:scale,shape
|
|
|
|
// g[ev]:loc,scale,shape
|
|
|
|
// fb_value, fb_key, fb_rate
|
|
|
|
|
|
|
|
class Generator {
|
|
|
|
public:
|
|
|
|
Generator() { }
|
|
|
|
// Generator(const Generator &g) = delete;
|
|
|
|
// virtual Generator& operator=(const Generator &g) = delete;
|
|
|
|
virtual ~Generator() { }
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0) = 0;
|
|
|
|
virtual void set_lambda(double) { DIE("set_lambda() not implemented"); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
std::string type;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Fixed : public Generator {
|
|
|
|
public:
|
|
|
|
Fixed(double _value = 1.0)
|
|
|
|
: value(_value)
|
|
|
|
{
|
|
|
|
D("Fixed(%f)", value);
|
|
|
|
}
|
|
|
|
virtual double generate(double) { return value; }
|
|
|
|
virtual void set_lambda(double lambda)
|
|
|
|
{
|
|
|
|
if (lambda > 0.0)
|
|
|
|
value = 1.0 / lambda;
|
|
|
|
else
|
|
|
|
value = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
double value;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Uniform : public Generator {
|
|
|
|
public:
|
|
|
|
Uniform(double _scale)
|
|
|
|
: scale(_scale)
|
|
|
|
{
|
|
|
|
D("Uniform(%f)", scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
if (U < 0.0)
|
|
|
|
U = drand48();
|
|
|
|
return scale * U;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void set_lambda(double lambda)
|
|
|
|
{
|
|
|
|
if (lambda > 0.0)
|
|
|
|
scale = 2.0 / lambda;
|
|
|
|
else
|
|
|
|
scale = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
double scale;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Normal : public Generator {
|
|
|
|
public:
|
|
|
|
Normal(double _mean = 1.0, double _sd = 1.0)
|
|
|
|
: mean(_mean)
|
|
|
|
, sd(_sd)
|
|
|
|
{
|
|
|
|
D("Normal(mean=%f, sd=%f)", mean, sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
if (U < 0.0)
|
|
|
|
U = drand48();
|
|
|
|
double V = U; // drand48();
|
|
|
|
double N = sqrt(-2 * log(U)) * cos(2 * M_PI * V);
|
|
|
|
return mean + sd * N;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void set_lambda(double lambda)
|
|
|
|
{
|
|
|
|
if (lambda > 0.0)
|
|
|
|
mean = 1.0 / lambda;
|
|
|
|
else
|
|
|
|
mean = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
double mean, sd;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Exponential : public Generator {
|
|
|
|
public:
|
|
|
|
Exponential(double _lambda = 1.0)
|
|
|
|
: lambda(_lambda)
|
|
|
|
{
|
|
|
|
D("Exponential(lambda=%f)", lambda);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
if (lambda <= 0.0)
|
|
|
|
return 0.0;
|
|
|
|
if (U < 0.0)
|
|
|
|
U = drand48();
|
|
|
|
return -log(U) / lambda;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void set_lambda(double lambda) { this->lambda = lambda; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
double lambda;
|
|
|
|
};
|
|
|
|
|
|
|
|
class GPareto : public Generator {
|
|
|
|
public:
|
|
|
|
GPareto(double _loc = 0.0, double _scale = 1.0, double _shape = 1.0)
|
|
|
|
: loc(_loc)
|
|
|
|
, scale(_scale)
|
|
|
|
, shape(_shape)
|
|
|
|
{
|
|
|
|
assert(shape != 0.0);
|
|
|
|
D("GPareto(loc=%f, scale=%f, shape=%f)", loc, scale, shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
if (U < 0.0)
|
|
|
|
U = drand48();
|
|
|
|
return loc + scale * (pow(U, -shape) - 1) / shape;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void set_lambda(double lambda)
|
|
|
|
{
|
|
|
|
if (lambda <= 0.0)
|
|
|
|
scale = 0.0;
|
|
|
|
else
|
|
|
|
scale = (1 - shape) / lambda - (1 - shape) * loc;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
double loc /* mu */;
|
|
|
|
double scale /* sigma */, shape /* k */;
|
|
|
|
};
|
|
|
|
|
|
|
|
class GEV : public Generator {
|
|
|
|
public:
|
|
|
|
GEV(double _loc = 0.0, double _scale = 1.0, double _shape = 1.0)
|
|
|
|
: e(1.0)
|
|
|
|
, loc(_loc)
|
|
|
|
, scale(_scale)
|
|
|
|
, shape(_shape)
|
|
|
|
{
|
|
|
|
assert(shape != 0.0);
|
|
|
|
D("GEV(loc=%f, scale=%f, shape=%f)", loc, scale, shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
return loc + scale * (pow(e.generate(U), -shape) - 1) / shape;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Exponential e;
|
|
|
|
double loc /* mu */, scale /* sigma */, shape /* k */;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Discrete : public Generator {
|
|
|
|
public:
|
|
|
|
~Discrete() { delete def; }
|
|
|
|
Discrete(Generator *_def = NULL)
|
|
|
|
: def(_def)
|
|
|
|
{
|
|
|
|
if (def == NULL)
|
|
|
|
def = new Fixed(0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual double generate(double U = -1.0)
|
|
|
|
{
|
|
|
|
double Uc = U;
|
|
|
|
if (pv.size() > 0 && U < 0.0)
|
|
|
|
U = drand48();
|
|
|
|
|
|
|
|
double sum = 0;
|
|
|
|
|
|
|
|
for (auto p : pv) {
|
|
|
|
sum += p.first;
|
|
|
|
if (U < sum)
|
|
|
|
return p.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
return def->generate(Uc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void add(double p, double v)
|
|
|
|
{
|
|
|
|
pv.push_back(std::pair<double, double>(p, v));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Generator *def;
|
|
|
|
std::vector<std::pair<double, double>> pv;
|
|
|
|
};
|
|
|
|
|
|
|
|
class KeyGenerator {
|
|
|
|
public:
|
|
|
|
KeyGenerator(Generator *_g, double _max = 10000)
|
|
|
|
: g(_g)
|
|
|
|
, max(_max)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
std::string generate(uint64_t ind)
|
|
|
|
{
|
|
|
|
uint64_t h = fnv_64(ind);
|
|
|
|
double U = (double)h / (double)ULLONG_MAX;
|
|
|
|
double G = g->generate(U);
|
|
|
|
int keylen = MAX(round(G), floor(log10(max)) + 1);
|
|
|
|
char key[256];
|
|
|
|
snprintf(key, 256, "%0*" PRIu64, keylen, ind);
|
|
|
|
|
|
|
|
// D("%d = %s", ind, key);
|
|
|
|
return std::string(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Generator *g;
|
|
|
|
double max;
|
|
|
|
};
|
|
|
|
|
|
|
|
Generator *createGenerator(std::string str);
|
|
|
|
Generator *createFacebookKey();
|
|
|
|
Generator *createFacebookValue();
|
|
|
|
Generator *createFacebookIA();
|
2022-06-22 15:40:48 +00:00
|
|
|
|
|
|
|
// memload generator
|
|
|
|
class memload_generator {
|
|
|
|
public:
|
|
|
|
struct memload_generator_options {
|
2022-11-11 21:11:50 +00:00
|
|
|
size_t transaction_size {4096};
|
|
|
|
size_t buffer_size {64*1024*1024};
|
|
|
|
char ia_dist[64]{"fixed"};
|
2022-06-22 15:40:48 +00:00
|
|
|
int verbose {0};
|
2022-11-16 07:44:43 +00:00
|
|
|
uint64_t trans_per_second;
|
2022-06-22 15:40:48 +00:00
|
|
|
bool shared_buffer {true};
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
DISALLOW_EVIL_CONSTRUCTORS(memload_generator);
|
|
|
|
struct thread_info {
|
|
|
|
pthread_t pthr;
|
|
|
|
void *from_buffer;
|
|
|
|
void *to_buffer;
|
2022-11-16 07:44:43 +00:00
|
|
|
std::atomic<bool> reset_ts;
|
2022-06-22 15:40:48 +00:00
|
|
|
int tid;
|
2023-05-01 19:28:51 +00:00
|
|
|
int pull;
|
2023-03-15 22:43:37 +00:00
|
|
|
int coreid;
|
|
|
|
int target_dom;
|
2022-06-22 15:40:48 +00:00
|
|
|
struct memload_generator_options * opts;
|
2023-03-15 22:43:37 +00:00
|
|
|
Generator * ia_gen;
|
2022-06-22 15:40:48 +00:00
|
|
|
|
|
|
|
// stat keeping
|
|
|
|
std::atomic<uint32_t> num_trans;
|
2022-11-01 10:01:23 +00:00
|
|
|
std::atomic<int> * state;
|
2023-03-15 22:43:37 +00:00
|
|
|
std::atomic<int> init_status;
|
2022-06-22 15:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<struct thread_info *> thr_infos;
|
2022-11-01 10:01:23 +00:00
|
|
|
std::atomic<int> state;
|
|
|
|
static constexpr int STATE_RUN = 0;
|
|
|
|
static constexpr int STATE_RDY = 1;
|
|
|
|
static constexpr int STATE_END = 2;
|
|
|
|
static constexpr int STATE_INIT = 3;
|
|
|
|
|
2022-06-22 15:40:48 +00:00
|
|
|
static void *worker_thrd(void *_tinfo);
|
2022-11-01 10:01:23 +00:00
|
|
|
struct memload_generator_options opts;
|
2022-06-22 15:40:48 +00:00
|
|
|
|
|
|
|
public:
|
2023-05-01 19:28:51 +00:00
|
|
|
memload_generator(cpuset_t * threads, cpuset_t * modes, cpuset_t * target_domain, struct memload_generator_options * opt, bool *success);
|
2022-11-01 10:01:23 +00:00
|
|
|
uint64_t get_transactions();
|
|
|
|
bool start();
|
|
|
|
bool stop();
|
2022-11-16 07:44:43 +00:00
|
|
|
bool set_transactions(uint64_t tps);
|
2022-06-22 15:40:48 +00:00
|
|
|
~memload_generator();
|
|
|
|
};
|