summaryrefslogtreecommitdiffstats
path: root/src/test/xattr_bench.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/xattr_bench.cc')
-rw-r--r--src/test/xattr_bench.cc199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/test/xattr_bench.cc b/src/test/xattr_bench.cc
new file mode 100644
index 000000000..7fac235be
--- /dev/null
+++ b/src/test/xattr_bench.cc
@@ -0,0 +1,199 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include "os/filestore/FileStore.h"
+#include "include/Context.h"
+#include "common/ceph_argparse.h"
+#include "common/ceph_mutex.h"
+#include "common/Cond.h"
+#include "global/global_init.h"
+#include <boost/scoped_ptr.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/binomial_distribution.hpp>
+#include <gtest/gtest.h>
+
+#include "include/unordered_map.h"
+
+void usage(const string &name) {
+ std::cerr << "Usage: " << name << " [xattr|omap] store_path store_journal"
+ << std::endl;
+}
+
+const int THREADS = 5;
+
+template <typename T>
+typename T::iterator rand_choose(T &cont) {
+ if (std::empty(cont) == 0) {
+ return std::end(cont);
+ }
+ return std::next(std::begin(cont), rand() % cont.size());
+}
+
+class OnApplied : public Context {
+public:
+ ceph::mutex *lock;
+ ceph::condition_variable *cond;
+ int *in_progress;
+ ObjectStore::Transaction *t;
+ OnApplied(ceph::mutex *lock,
+ ceph::condition_variable *cond,
+ int *in_progress,
+ ObjectStore::Transaction *t)
+ : lock(lock), cond(cond),
+ in_progress(in_progress), t(t) {
+ std::lock_guard l{*lock};
+ (*in_progress)++;
+ }
+
+ void finish(int r) override {
+ std::lock_guard l{*lock};
+ (*in_progress)--;
+ cond->notify_all();
+ }
+};
+
+uint64_t get_time() {
+ time_t start;
+ time(&start);
+ return start * 1000;
+}
+
+double print_time(uint64_t ms) {
+ return ((double)ms)/1000;
+}
+
+uint64_t do_run(ObjectStore *store, int attrsize, int numattrs,
+ int run,
+ int transsize, int ops,
+ ostream &out) {
+ ceph::mutex lock = ceph::make_mutex("lock");
+ ceph::condition_variable cond;
+ int in_flight = 0;
+ ObjectStore::Sequencer osr(__func__);
+ ObjectStore::Transaction t;
+ map<coll_t, pair<set<string>, ObjectStore::Sequencer*> > collections;
+ for (int i = 0; i < 3*THREADS; ++i) {
+ coll_t coll(spg_t(pg_t(0, i + 1000*run), shard_id_t::NO_SHARD));
+ t.create_collection(coll, 0);
+ set<string> objects;
+ for (int i = 0; i < transsize; ++i) {
+ stringstream obj_str;
+ obj_str << i;
+ t.touch(coll,
+ ghobject_t(hobject_t(sobject_t(obj_str.str(), CEPH_NOSNAP))));
+ objects.insert(obj_str.str());
+ }
+ collections[coll] = make_pair(objects, new ObjectStore::Sequencer(coll.to_str()));
+ }
+ store->queue_transaction(&osr, std::move(t));
+
+ bufferlist bl;
+ for (int i = 0; i < attrsize; ++i) {
+ bl.append('\0');
+ }
+
+ uint64_t start = get_time();
+ for (int i = 0; i < ops; ++i) {
+ {
+ std::unique_lock l{lock};
+ cond.wait(l, [&] { in_flight < THREADS; });
+ }
+ ObjectStore::Transaction *t = new ObjectStore::Transaction;
+ map<coll_t, pair<set<string>, ObjectStore::Sequencer*> >::iterator iter =
+ rand_choose(collections);
+ for (set<string>::iterator obj = iter->second.first.begin();
+ obj != iter->second.first.end();
+ ++obj) {
+ for (int j = 0; j < numattrs; ++j) {
+ stringstream ss;
+ ss << i << ", " << j << ", " << *obj;
+ t->setattr(iter->first,
+ ghobject_t(hobject_t(sobject_t(*obj, CEPH_NOSNAP))),
+ ss.str().c_str(),
+ bl);
+ }
+ }
+ store->queue_transaction(iter->second.second, std::move(*t),
+ new OnApplied(&lock, &cond, &in_flight,
+ t));
+ delete t;
+ }
+ {
+ std::unique_lock l{lock};
+ cond.wait(l, [&] { return in_flight == 0; });
+ }
+ return get_time() - start;
+}
+
+int main(int argc, char **argv) {
+ vector<const char*> args;
+ argv_to_vec(argc, (const char **)argv, args);
+ if (args.empty()) {
+ cerr << argv[0] << ": -h or --help for usage" << std::endl;
+ exit(1);
+ }
+ if (ceph_argparse_need_usage(args)) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ auto cct = global_init(0, args, CEPH_ENTITY_TYPE_CLIENT,
+ CODE_ENVIRONMENT_UTILITY,
+ CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
+ common_init_finish(g_ceph_context);
+
+ std::cerr << "args: " << args << std::endl;
+ if (args.size() < 3) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ string store_path(args[1]);
+ string store_dev(args[2]);
+
+ boost::scoped_ptr<ObjectStore> store(new FileStore(cct.get(), store_path,
+ store_dev));
+
+ std::cerr << "mkfs starting" << std::endl;
+ ceph_assert(!store->mkfs());
+ ceph_assert(!store->mount());
+ std::cerr << "mounted" << std::endl;
+
+ std::cerr << "attrsize\tnumattrs\ttranssize\tops\ttime" << std::endl;
+ int runs = 0;
+ int total_size = 11;
+ for (int i = 6; i < total_size; ++i) {
+ for (int j = (total_size - i); j >= 0; --j) {
+ std::cerr << "starting run " << runs << std::endl;
+ ++runs;
+ uint64_t time = do_run(store.get(), (1 << i), (1 << j), runs,
+ 10,
+ 1000, std::cout);
+ std::cout << (1 << i) << "\t"
+ << (1 << j) << "\t"
+ << 10 << "\t"
+ << 1000 << "\t"
+ << print_time(time) << std::endl;
+ }
+ }
+ store->umount();
+ return 0;
+}