// -*- 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) 2014 UnitedStack * * Author: Haomai Wang * * 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 #include #include #include using namespace std; #include "common/ceph_argparse.h" #include "common/debug.h" #include "common/Cycles.h" #include "global/global_init.h" #include "os/ObjectStore.h" class Transaction { private: ObjectStore::Transaction t; public: struct Tick { uint64_t ticks; uint64_t count; Tick(): ticks(0), count(0) {} void add(uint64_t a) { ticks += a; count++; } }; static Tick write_ticks, setattr_ticks, omap_setkeys_ticks, omap_rmkeys_ticks; static Tick encode_ticks, decode_ticks, iterate_ticks; void write(coll_t cid, const ghobject_t& oid, uint64_t off, uint64_t len, const bufferlist& data) { uint64_t start_time = Cycles::rdtsc(); t.write(cid, oid, off, len, data); write_ticks.add(Cycles::rdtsc() - start_time); } void setattr(coll_t cid, const ghobject_t& oid, const string &name, bufferlist& val) { uint64_t start_time = Cycles::rdtsc(); t.setattr(cid, oid, name, val); setattr_ticks.add(Cycles::rdtsc() - start_time); } void omap_setkeys(coll_t cid, const ghobject_t &oid, const map &attrset) { uint64_t start_time = Cycles::rdtsc(); t.omap_setkeys(cid, oid, attrset); omap_setkeys_ticks.add(Cycles::rdtsc() - start_time); } void omap_rmkeys(coll_t cid, const ghobject_t &oid, const set &keys) { uint64_t start_time = Cycles::rdtsc(); t.omap_rmkeys(cid, oid, keys); omap_rmkeys_ticks.add(Cycles::rdtsc() - start_time); } void apply_encode_decode() { bufferlist bl; ObjectStore::Transaction d; uint64_t start_time = Cycles::rdtsc(); t.encode(bl); encode_ticks.add(Cycles::rdtsc() - start_time); bufferlist::iterator bliter = bl.begin(); start_time = Cycles::rdtsc(); d.decode(bliter); decode_ticks.add(Cycles::rdtsc() - start_time); } void apply_iterate() { uint64_t start_time = Cycles::rdtsc(); ObjectStore::Transaction::iterator i = t.begin(); while (i.have_op()) { ObjectStore::Transaction::Op *op = i.decode_op(); switch (op->op) { case ObjectStore::Transaction::OP_WRITE: { ghobject_t oid = i.get_oid(op->oid); bufferlist bl; i.decode_bl(bl); } break; case ObjectStore::Transaction::OP_SETATTR: { ghobject_t oid = i.get_oid(op->oid); string name = i.decode_string(); bufferlist bl; i.decode_bl(bl); map to_set; to_set[name] = bufferptr(bl.c_str(), bl.length()); } break; case ObjectStore::Transaction::OP_OMAP_SETKEYS: { ghobject_t oid = i.get_oid(op->oid); map aset; i.decode_attrset(aset); } break; case ObjectStore::Transaction::OP_OMAP_RMKEYS: { ghobject_t oid = i.get_oid(op->oid); set keys; i.decode_keyset(keys); } break; } } iterate_ticks.add(Cycles::rdtsc() - start_time); } static void dump_stat() { cerr << " write op: " << Cycles::to_microseconds(write_ticks.ticks) << "us count: " << write_ticks.count << std::endl; cerr << " setattr op: " << Cycles::to_microseconds(setattr_ticks.ticks) << "us count: " << setattr_ticks.count << std::endl; cerr << " omap_setkeys op: " << Cycles::to_microseconds(Transaction::omap_setkeys_ticks.ticks) << "us count: " << Transaction::omap_setkeys_ticks.count << std::endl; cerr << " omap_rmkeys op: " << Cycles::to_microseconds(Transaction::omap_rmkeys_ticks.ticks) << "us count: " << Transaction::omap_rmkeys_ticks.count << std::endl; cerr << " encode op: " << Cycles::to_microseconds(Transaction::encode_ticks.ticks) << "us count: " << Transaction::encode_ticks.count << std::endl; cerr << " decode op: " << Cycles::to_microseconds(Transaction::decode_ticks.ticks) << "us count: " << Transaction::decode_ticks.count << std::endl; cerr << " iterate op: " << Cycles::to_microseconds(Transaction::iterate_ticks.ticks) << "us count: " << Transaction::iterate_ticks.count << std::endl; } }; class PerfCase { static const uint64_t Kib = 1024; static const uint64_t Mib = 1024 * 1024; static const string info_epoch_attr; static const string info_info_attr; static const string attr; static const string snapset_attr; static const string pglog_attr; static const coll_t meta_cid; static const coll_t cid; static const ghobject_t pglog_oid; static const ghobject_t info_oid; map data; ghobject_t create_object() { bufferlist bl = generate_random(100, 1); return ghobject_t(hobject_t(string("obj_")+string(bl.c_str()), string(), rand() & 2 ? CEPH_NOSNAP : rand(), rand() & 0xFF, 0, "")); } bufferlist generate_random(uint64_t len, int frag) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; uint64_t per_frag = len / frag; bufferlist bl; for (int i = 0; i < frag; i++ ) { bufferptr bp(per_frag); for (unsigned int j = 0; j < len; j++) { bp[j] = alphanum[rand() % (sizeof(alphanum) - 1)]; } bl.append(bp); } return bl; } public: PerfCase() { uint64_t four_kb = Kib * 4; uint64_t one_mb = Mib * 1; uint64_t four_mb = Mib * 4; data["4k"] = generate_random(four_kb, 1); data["1m"] = generate_random(one_mb, 1); data["4m"] = generate_random(four_mb, 1); data[attr] = generate_random(256, 1); data[snapset_attr] = generate_random(32, 1); data[pglog_attr] = generate_random(128, 1); data[info_epoch_attr] = generate_random(4, 1); data[info_info_attr] = generate_random(560, 1); } uint64_t rados_write_4k(int times) { uint64_t ticks = 0; uint64_t len = Kib *4; for (int i = 0; i < times; i++) { uint64_t start_time = 0; { Transaction t; ghobject_t oid = create_object(); start_time = Cycles::rdtsc(); t.write(cid, oid, 0, len, data["4k"]); t.setattr(cid, oid, attr, data[attr]); t.setattr(cid, oid, snapset_attr, data[snapset_attr]); t.apply_encode_decode(); t.apply_iterate(); ticks += Cycles::rdtsc() - start_time; } { Transaction t; map pglog_attrset; map info_attrset; set keys; keys.insert(pglog_attr); pglog_attrset[pglog_attr] = data[pglog_attr]; info_attrset[info_epoch_attr] = data[info_epoch_attr]; info_attrset[info_info_attr] = data[info_info_attr]; start_time = Cycles::rdtsc(); t.omap_setkeys(meta_cid, pglog_oid, pglog_attrset); t.omap_setkeys(meta_cid, info_oid, info_attrset); t.omap_rmkeys(meta_cid, pglog_oid, keys); t.apply_encode_decode(); t.apply_iterate(); ticks += Cycles::rdtsc() - start_time; } } return ticks; } }; const string PerfCase::info_epoch_attr("11.40_epoch"); const string PerfCase::info_info_attr("11.40_info"); const string PerfCase::attr("_"); const string PerfCase::snapset_attr("snapset"); const string PerfCase::pglog_attr("pglog_attr"); const coll_t PerfCase::meta_cid; const coll_t PerfCase::cid; const ghobject_t PerfCase::pglog_oid(hobject_t(sobject_t(object_t("cid_pglog"), 0))); const ghobject_t PerfCase::info_oid(hobject_t(sobject_t(object_t("infos"), 0))); Transaction::Tick Transaction::write_ticks, Transaction::setattr_ticks, Transaction::omap_setkeys_ticks, Transaction::omap_rmkeys_ticks; Transaction::Tick Transaction::encode_ticks, Transaction::decode_ticks, Transaction::iterate_ticks; void usage(const string &name) { cerr << "Usage: " << name << " [times] " << std::endl; } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); Cycles::init(); cerr << "args: " << args << std::endl; if (args.size() < 1) { usage(argv[0]); return 1; } uint64_t times = atoi(args[0]); PerfCase c; uint64_t ticks = c.rados_write_4k(times); Transaction::dump_stat(); cerr << " Total rados op " << times << " run time " << Cycles::to_microseconds(ticks) << "us." << std::endl; return 0; }