summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoao Eduardo Luis <jecluis@gmail.com>2012-03-13 16:12:38 +0000
committerJoao Eduardo Luis <jecluis@gmail.com>2012-03-28 01:22:01 +0100
commit3770096a0a195b0a8eb00c42d2ba76281763a13c (patch)
treef0206b598889a561a7e414c23b15797deada4798
parentd5360968617ebb7e7b6fcb1026c2c11e53b8833a (diff)
downloadceph-3770096a0a195b0a8eb00c42d2ba76281763a13c.tar.gz
test: test_workload_gen: Mimic an OSD's workload.
In it's current state, the workload generator will queue a lot of transactions onto the FileStore, and will wait if needed in case there are too many in-flight transactions. The workload generator will perform the transactions over a pre-determined number of collections and objects, which may very well be defined at runtime by using the options '-C <VAL>' and '-O <VAL>' for collections and objects per collection, respectively. If these are not provided, the program will default to 30 collections and 6000 objects per collection.
-rw-r--r--src/Makefile.am6
-rw-r--r--src/test/test_workload_gen/workload_generator.cc276
-rw-r--r--src/test/test_workload_gen/workload_generator.h118
3 files changed, 400 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4440d046fde..129ecc86bed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -710,6 +710,12 @@ test_store_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} \
-I$(top_srcdir)/src/leveldb/include
bin_DEBUGPROGRAMS += test_store
+test_wrkldgen_SOURCES = test/test_workload_gen/workload_generator.cc
+test_wrkldgen_LDFLAGS = ${AM_LDFLAGS}
+test_wrkldgen_LDADD = ${UNITTEST_STATIC_LDADD} libos.la $(LIBGLOBAL_LDA)
+test_wrkldgen_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+bin_DEBUGPROGRAMS += test_wrkldgen
+
xattr_bench_SOURCES = test/xattr_bench.cc
xattr_bench_LDFLAGS = ${AM_LDFLAGS}
xattr_bench_LDADD = ${UNITTEST_STATIC_LDADD} libos.la leveldb/libleveldb.a $(LIBGLOBAL_LDA)
diff --git a/src/test/test_workload_gen/workload_generator.cc b/src/test/test_workload_gen/workload_generator.cc
new file mode 100644
index 00000000000..7762440badc
--- /dev/null
+++ b/src/test/test_workload_gen/workload_generator.cc
@@ -0,0 +1,276 @@
+/*
+ * workload_generator.cc
+ *
+ * Created on: Mar 12, 2012
+ * Author: jecluis
+ */
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "os/FileStore.h"
+#include "common/ceph_argparse.h"
+#include "global/global_init.h"
+#include "common/debug.h"
+#include <boost/scoped_ptr.hpp>
+#include "workload_generator.h"
+
+boost::scoped_ptr<WorkloadGenerator> wrkldgen;
+const coll_t WorkloadGenerator::META_COLL("meta");
+const coll_t WorkloadGenerator::TEMP_COLL("temp");
+
+void sig_handler(int sig) {
+ if (sig == SIGINT) {
+ wrkldgen->stop();
+ }
+}
+
+WorkloadGenerator::WorkloadGenerator(vector<const char*> args) :
+ NUM_COLLS(DEF_NUM_COLLS),
+ NUM_OBJ_PER_COLL(DEF_NUM_OBJ_PER_COLL),
+ store(0), rng(time(NULL)), in_flight(0),
+ lock("State Lock"), stop_running(false)
+{
+ init_args(args);
+
+ ::mkdir("workload_gen_dir", 0777);
+ ObjectStore *store_ptr = new FileStore(string("workload_gen_dir"),
+ string("workload_gen_journal"));
+ store.reset(store_ptr);
+ store->mkfs();
+ store->mount();
+
+ osr = new ObjectStore::Sequencer[NUM_COLLS];
+
+ init();
+}
+
+void WorkloadGenerator::init_args(vector<const char*> args) {
+ for (std::vector<const char*>::iterator i = args.begin();
+ i != args.end(); ) {
+ string val;
+
+ if (ceph_argparse_double_dash(args, i)) {
+ break;
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "-C", "--num-collections", (char*)NULL)) {
+ NUM_COLLS = strtoll(val.c_str(), NULL, 10);
+ } else if (ceph_argparse_witharg(args, i, &val,
+ "-O", "--num-objects", (char*)NULL)) {
+ NUM_OBJ_PER_COLL = strtoll(val.c_str(), NULL, 10);
+ }
+// else if (ceph_argparse_witharg(args, i, &val,
+// "-o", "--outfn", (char*)NULL)) {
+// outfn = val;
+// }
+ }
+}
+
+void WorkloadGenerator::init() {
+
+ dout(0) << "Initializing..." << dendl;
+
+ ObjectStore::Transaction *t = new ObjectStore::Transaction;
+
+ t->create_collection(META_COLL);
+ t->create_collection(TEMP_COLL);
+// store->queue_transaction(&osr, t);
+ store->apply_transaction(*t);
+
+ wait_for_ready();
+
+ char buf[100];
+ for (int i = 0; i < NUM_COLLS; i ++) {
+ memset(buf, 0, 100);
+ snprintf(buf, 100, "0.%d_head", i);
+ coll_t coll(buf);
+
+ dout(0) << "Creating collection " << coll.to_str() << dendl;
+
+ t = new ObjectStore::Transaction;
+
+ t->create_collection(coll);
+
+ memset(buf, 0, 100);
+ snprintf(buf, 100, "pglog_0.%d_head", i);
+ hobject_t coll_meta_obj(sobject_t(object_t(buf), CEPH_NOSNAP));
+ t->touch(META_COLL, coll_meta_obj);
+
+ store->queue_transaction(&osr[i], t,
+ new C_WorkloadGeneratorOnReadable(this, t));
+ in_flight++;
+ }
+
+ wait_for_done();
+ dout(0) << "Done initializing!" << dendl;
+}
+
+int WorkloadGenerator::get_random_collection_nr() {
+ return (rand() % NUM_COLLS);
+}
+
+int WorkloadGenerator::get_random_object_nr(int coll_nr) {
+ return ((rand() % NUM_OBJ_PER_COLL) + (coll_nr*NUM_OBJ_PER_COLL));
+}
+
+coll_t WorkloadGenerator::get_collection_by_nr(int nr) {
+
+ char buf[100];
+ memset(buf, 0, 100);
+
+ snprintf(buf, 100, "0.%d_head", nr);
+ return coll_t(buf);
+}
+
+hobject_t WorkloadGenerator::get_object_by_nr(int nr) {
+
+ char buf[100];
+ memset(buf, 0, 100);
+ snprintf(buf, 100, "%d", nr);
+
+ return hobject_t(sobject_t(object_t(buf), CEPH_NOSNAP));
+}
+
+hobject_t WorkloadGenerator::get_coll_meta_object(coll_t coll) {
+ char buf[100];
+ memset(buf, 0, 100);
+ snprintf(buf, 100, "pglog_%s", coll.c_str());
+
+ return hobject_t(sobject_t(object_t(buf), CEPH_NOSNAP));
+}
+
+/**
+ * We'll generate a random amount of bytes, ranging from a single byte up to
+ * a couple of MB.
+ */
+size_t WorkloadGenerator::get_random_byte_amount(size_t min, size_t max) {
+ size_t diff = max - min;
+
+ return (size_t) (min + (rand() % diff));
+}
+
+void WorkloadGenerator::get_filled_byte_array(bufferlist& bl, size_t size) {
+
+ static const char alphanum[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ bufferptr bp(size);
+ for (unsigned int i = 0; i < size-1; i ++) {
+ bp[i] = alphanum[rand() % sizeof(alphanum)];
+ }
+ bp[size-1] = '\0';
+ bl.append(bp);
+}
+
+int WorkloadGenerator::do_write_object(ObjectStore::Transaction *t,
+ coll_t coll, hobject_t obj) {
+
+ size_t bytes = get_random_byte_amount(MIN_WRITE_BYTES, MAX_WRITE_BYTES);
+ bufferlist bl;
+ get_filled_byte_array(bl, bytes);
+ t->write(coll, obj, 0, bl.length(), bl);
+
+ return 0;
+}
+
+int WorkloadGenerator::do_setattr_object(ObjectStore::Transaction *t,
+ coll_t coll, hobject_t obj) {
+ size_t size;
+ size = get_random_byte_amount(MIN_XATTR_OBJ_BYTES, MAX_XATTR_OBJ_BYTES);
+
+ bufferlist bl;
+ get_filled_byte_array(bl, size);
+ t->setattr(coll, obj, "objxattr", bl);
+
+ return 0;
+}
+
+int WorkloadGenerator::do_setattr_collection(ObjectStore::Transaction *t,
+ coll_t coll) {
+
+ size_t size;
+ size = get_random_byte_amount(MIN_XATTR_COLL_BYTES, MAX_XATTR_COLL_BYTES);
+
+ bufferlist bl;
+ get_filled_byte_array(bl, size);
+ t->collection_setattr(coll, "collxattr", bl);
+
+ return 0;
+}
+
+int WorkloadGenerator::do_append_log(ObjectStore::Transaction *t,
+ coll_t coll) {
+
+ bufferlist bl;
+ get_filled_byte_array(bl, LOG_APPEND_BYTES);
+ hobject_t log_obj = get_coll_meta_object(coll);
+
+ struct stat st;
+ int err = store->stat(META_COLL, log_obj, &st);
+ assert(err >= 0);
+ t->write(META_COLL, log_obj, st.st_size, bl.length(), bl);
+
+ return 0;
+}
+
+void WorkloadGenerator::run() {
+
+ do {
+ lock.Lock();
+ wait_for_ready();
+
+ int coll_nr = get_random_collection_nr();
+ int obj_nr = get_random_object_nr(coll_nr);
+ coll_t coll = get_collection_by_nr(coll_nr);
+ hobject_t obj = get_object_by_nr(obj_nr);
+
+ ObjectStore::Transaction *t = new ObjectStore::Transaction;
+ int err;
+
+ err = do_write_object(t, coll, obj);
+ assert(err == 0);
+
+ err = do_setattr_object(t, coll, obj);
+ assert(err == 0);
+
+ err = do_setattr_collection(t, coll);
+ assert(err == 0);
+
+ err = do_append_log(t, coll);
+ assert(err == 0);
+
+ store->queue_transaction(&osr[coll_nr], t,
+ new C_WorkloadGeneratorOnReadable(this, t));
+
+ in_flight++;
+
+ lock.Unlock();
+ } while (!stop_running);
+}
+
+void WorkloadGenerator::print_results() {
+
+}
+
+
+int main(int argc, char *argv[]) {
+ vector<const char*> args;
+ argv_to_vec(argc, (const char **)argv, args);
+
+ global_init(args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0);
+ common_init_finish(g_ceph_context);
+ g_ceph_context->_conf->set_val("osd_journal_size", "400");
+ g_ceph_context->_conf->apply_changes(NULL);
+
+
+ WorkloadGenerator *wrkldgen_ptr = new WorkloadGenerator(args);
+ wrkldgen.reset(wrkldgen_ptr);
+ wrkldgen->run();
+ wrkldgen->print_results();
+
+ return 0;
+}
diff --git a/src/test/test_workload_gen/workload_generator.h b/src/test/test_workload_gen/workload_generator.h
new file mode 100644
index 00000000000..efe2538b924
--- /dev/null
+++ b/src/test/test_workload_gen/workload_generator.h
@@ -0,0 +1,118 @@
+/*
+ * workload_generator.h
+ *
+ * Created on: Mar 12, 2012
+ * Author: jecluis
+ */
+
+#ifndef WORKLOAD_GENERATOR_H_
+#define WORKLOAD_GENERATOR_H_
+
+#include "os/FileStore.h"
+#include <boost/scoped_ptr.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <pthread.h>
+
+typedef boost::mt11213b gen_type;
+
+class WorkloadGenerator
+{
+private:
+ static const int NUM_THREADS = 2;
+ static const int MAX_IN_FLIGHT = 50;
+
+ static const int DEF_NUM_OBJ_PER_COLL = 6000;
+ static const int DEF_NUM_COLLS = 30;
+
+ static const coll_t META_COLL;
+ static const coll_t TEMP_COLL;
+
+ static const size_t MIN_WRITE_BYTES = 1;
+ static const size_t MAX_WRITE_MB = 5;
+ static const size_t MAX_WRITE_BYTES = (MAX_WRITE_MB * 1024 * 1024);
+
+ static const size_t MIN_XATTR_OBJ_BYTES = 2;
+ static const size_t MAX_XATTR_OBJ_BYTES = 300;
+ static const size_t MIN_XATTR_COLL_BYTES = 4;
+ static const size_t MAX_XATTR_COLL_BYTES = 600;
+// static const size_t XATTR_NAME_BYTES = 30;
+
+ static const size_t LOG_APPEND_BYTES = 1024;
+
+ int NUM_COLLS;
+ int NUM_OBJ_PER_COLL;
+
+ boost::scoped_ptr<ObjectStore> store;
+
+ gen_type rng;
+ int in_flight;
+ ObjectStore::Sequencer *osr;
+
+ Mutex lock;
+ Cond cond;
+
+ bool stop_running;
+
+ void wait_for_ready() {
+ while (in_flight >= MAX_IN_FLIGHT)
+ cond.Wait(lock);
+ }
+
+ void wait_for_done() {
+ Mutex::Locker locker(lock);
+ while (in_flight)
+ cond.Wait(lock);
+ }
+
+ void init_args(vector<const char*> args);
+ void init();
+
+ int get_random_collection_nr();
+ int get_random_object_nr(int coll_nr);
+
+ coll_t get_collection_by_nr(int nr);
+ hobject_t get_object_by_nr(int nr);
+ hobject_t get_coll_meta_object(coll_t coll);
+
+ size_t get_random_byte_amount(size_t min, size_t max);
+ void get_filled_byte_array(bufferlist& bl, size_t size);
+
+ int do_write_object(ObjectStore::Transaction *t,
+ coll_t coll, hobject_t obj);
+ int do_setattr_object(ObjectStore::Transaction *t,
+ coll_t coll, hobject_t obj);
+ int do_setattr_collection(ObjectStore::Transaction *t, coll_t coll);
+ int do_append_log(ObjectStore::Transaction *t, coll_t coll);
+
+public:
+ WorkloadGenerator(vector<const char*> args);
+ ~WorkloadGenerator() {
+ store->umount();
+ }
+
+ class C_WorkloadGeneratorOnReadable : public Context {
+ WorkloadGenerator *state;
+ ObjectStore::Transaction *t;
+
+ public:
+ C_WorkloadGeneratorOnReadable(WorkloadGenerator *state,
+ ObjectStore::Transaction *t) : state(state), t(t) {}
+
+ void finish(int r) {
+ dout(0) << "Got one back!" << dendl;
+ Mutex::Locker locker(state->lock);
+ state->in_flight--;
+ state->cond.Signal();
+ }
+ };
+
+
+ void run(void);
+ void print_results(void);
+ void stop() {
+ stop_running = true;
+ }
+};
+
+#endif /* WORKLOAD_GENERATOR_H_ */