// modified from mutilate // -*- c++ -*- // 1. implement "fixed" generator // 2. implement discrete generator // 3. implement combine generator? #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.hh" #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(p, v)); } private: Generator *def; std::vector> 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(); // memload generator class memload_generator { public: struct memload_generator_options { size_t transaction_size {4096}; size_t buffer_size {64*1024*1024}; char ia_dist[64]{"fixed"}; int verbose {0}; uint64_t trans_per_second; bool shared_buffer {true}; }; private: DISALLOW_EVIL_CONSTRUCTORS(memload_generator); struct thread_info { pthread_t pthr; void *from_buffer; void *to_buffer; std::atomic reset_ts; Generator * ia_gen; int tid; struct memload_generator_options * opts; // stat keeping std::atomic num_trans; std::atomic * state; std::atomic * init_num; }; std::vector thr_infos; std::atomic state; std::atomic init_num; static constexpr int STATE_RUN = 0; static constexpr int STATE_RDY = 1; static constexpr int STATE_END = 2; static constexpr int STATE_INIT = 3; static void *worker_thrd(void *_tinfo); struct memload_generator_options opts; public: memload_generator(cpuset_t * threads, cpuset_t * target_domain, struct memload_generator_options * opt, bool *success); uint64_t get_transactions(); bool start(); bool stop(); bool set_transactions(uint64_t tps); ~memload_generator(); };