From e8693eae21cde4d85738eb45d77997e28daa6fe9 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Tue, 10 Apr 2018 10:15:58 -0700 Subject: [PATCH] Serialize/Deserialize TargetProfiles Summary: When serializing or deserializing profile data, we now include all the TargetProfiles. Reviewed By: swtaarrs Differential Revision: D7553135 fbshipit-source-id: 1106531d4a56dc2706c56731c29030b15059aae8 --- hphp/runtime/base/rds.cpp | 26 ++++-- hphp/runtime/base/rds.h | 2 + hphp/runtime/vm/jit/meth-profile.cpp | 14 +++ hphp/runtime/vm/jit/meth-profile.h | 8 +- hphp/runtime/vm/jit/prof-data-serialize.cpp | 133 ++++++++++++++++++++++++++++ hphp/runtime/vm/jit/target-profile.h | 11 ++- 6 files changed, 187 insertions(+), 7 deletions(-) diff --git a/hphp/runtime/base/rds.cpp b/hphp/runtime/base/rds.cpp index 80dd4c37855..90e868d9f08 100644 --- a/hphp/runtime/base/rds.cpp +++ b/hphp/runtime/base/rds.cpp @@ -198,9 +198,14 @@ struct HashCompare { } }; +struct LinkEntry { + Handle handle; + uint32_t size; +}; + using LinkTable = tbb::concurrent_hash_map< Symbol, - Handle, + LinkEntry, HashCompare >; LinkTable s_linkTable; @@ -397,17 +402,19 @@ Handle allocUnlocked(Mode mode, size_t numBytes, Handle bindImpl(Symbol key, Mode mode, size_t sizeBytes, size_t align, type_scan::Index tyIndex) { LinkTable::const_accessor acc; - if (s_linkTable.find(acc, key)) return acc->second; + if (s_linkTable.find(acc, key)) return acc->second.handle; Guard g(s_allocMutex); - if (s_linkTable.find(acc, key)) return acc->second; + if (s_linkTable.find(acc, key)) return acc->second.handle; auto const handle = alloc(mode, sizeBytes, align, tyIndex); recordRds(handle, sizeBytes, key); LinkTable::const_accessor insert_acc; // insert_acc lives until after s_handleTable is updated - if (!s_linkTable.insert(insert_acc, LinkTable::value_type(key, handle))) { + if (!s_linkTable.insert( + insert_acc, + LinkTable::value_type(key, {handle, safe_cast(sizeBytes)}))) { always_assert(0); } if (type_scan::hasScanner(tyIndex)) { @@ -418,7 +425,7 @@ Handle bindImpl(Symbol key, Mode mode, size_t sizeBytes, Handle attachImpl(Symbol key) { LinkTable::const_accessor acc; - if (s_linkTable.find(acc, key)) return acc->second; + if (s_linkTable.find(acc, key)) return acc->second.handle; return kUninitHandle; } @@ -472,6 +479,15 @@ void unbind(Symbol key, Handle handle) { using namespace detail; +void visitSymbols(std::function fun) { + Guard g(s_allocMutex); + // make sure that find/count don't interfere with iteration. + s_linkTable.rehash(); + for (auto it : s_linkTable) { + fun(it.first, it.second.handle, it.second.size); + } +} + ////////////////////////////////////////////////////////////////////// __thread void* tl_base = nullptr; diff --git a/hphp/runtime/base/rds.h b/hphp/runtime/base/rds.h index 317c1a720da..d58448a5be9 100644 --- a/hphp/runtime/base/rds.h +++ b/hphp/runtime/base/rds.h @@ -551,6 +551,8 @@ void recordRds(Handle h, size_t size, const std::string& type, const std::string& msg); void recordRds(Handle h, size_t size, const Symbol& sym); +void visitSymbols(std::function fun); + /* * Return a list of all the tl_bases for any threads that are using RDS */ diff --git a/hphp/runtime/vm/jit/meth-profile.cpp b/hphp/runtime/vm/jit/meth-profile.cpp index 605811967ed..844906f6fb7 100644 --- a/hphp/runtime/vm/jit/meth-profile.cpp +++ b/hphp/runtime/vm/jit/meth-profile.cpp @@ -18,6 +18,7 @@ #include "hphp/runtime/vm/class.h" #include "hphp/runtime/vm/func.h" +#include "hphp/runtime/vm/jit/prof-data-serialize.h" #include "hphp/util/assertions.h" @@ -132,6 +133,19 @@ std::string MethProfile::toString() const { return std::string("none"); } +void MethProfile::serialize(ProfDataSerializer& ser) const { + write_raw(ser, curTag()); + write_func(ser, rawMeth()); + write_class(ser, rawClass()); +} + +void MethProfile::deserialize(ProfDataDeserializer& ser) { + auto const tag = read_raw(ser); + auto const func = read_func(ser); + setMeth(func, tag); + m_curClass = read_class(ser); +} + /////////////////////////////////////////////////////////////////////////////// }} diff --git a/hphp/runtime/vm/jit/meth-profile.h b/hphp/runtime/vm/jit/meth-profile.h index e4a91dac552..6fb143fa683 100644 --- a/hphp/runtime/vm/jit/meth-profile.h +++ b/hphp/runtime/vm/jit/meth-profile.h @@ -31,10 +31,13 @@ namespace jit { /////////////////////////////////////////////////////////////////////////////// +struct ProfDataSerializer; +struct ProfDataDeserializer; + struct MethProfile { using RawType = LowPtr::storage_type; - enum class Tag { + enum class Tag : uint8_t { UniqueClass = 0, UniqueMeth = 1, BaseMeth = 2, @@ -89,6 +92,9 @@ struct MethProfile { */ static void reduce(MethProfile& a, const MethProfile& b); + void serialize(ProfDataSerializer&) const; + void deserialize(ProfDataDeserializer&); + ///////////////////////////////////////////////////////////////////////////// private: diff --git a/hphp/runtime/vm/jit/prof-data-serialize.cpp b/hphp/runtime/vm/jit/prof-data-serialize.cpp index 461f7c18056..72cd06a5c04 100644 --- a/hphp/runtime/vm/jit/prof-data-serialize.cpp +++ b/hphp/runtime/vm/jit/prof-data-serialize.cpp @@ -26,6 +26,14 @@ #include "hphp/runtime/vm/class.h" #include "hphp/runtime/vm/func.h" +#include "hphp/runtime/vm/jit/array-kind-profile.h" +#include "hphp/runtime/vm/jit/array-offset-profile.h" +#include "hphp/runtime/vm/jit/cls-cns-profile.h" +#include "hphp/runtime/vm/jit/meth-profile.h" +#include "hphp/runtime/vm/jit/profile-refcount.h" +#include "hphp/runtime/vm/jit/release-vv-profile.h" +#include "hphp/runtime/vm/jit/switch-profile.h" +#include "hphp/runtime/vm/jit/type-profile.h" #include "hphp/runtime/vm/jit/containers.h" #include "hphp/runtime/vm/jit/prof-data.h" #include "hphp/runtime/vm/jit/trans-cfg.h" @@ -411,6 +419,127 @@ void read_prof_data(ProfDataDeserializer& ser, ProfData* pd) { } } +template +auto write_impl(ProfDataSerializer& ser, const T& out, bool) -> + decltype(std::declval().serialize(ser),void()) { + out.serialize(ser); +} + +template +void write_impl(ProfDataSerializer& ser, const T& out, int) { + write_raw(ser, out); +} + +template +void write_maybe_serializable(ProfDataSerializer& ser, const T& out) { + write_impl(ser, out, false); +} + +struct TargetProfileVisitor : boost::static_visitor { + TargetProfileVisitor(ProfDataSerializer& ser, + const rds::Symbol& sym, + rds::Handle handle, + uint32_t size) : + ser{ser}, + sym{sym}, + handle{handle}, + size{size} {} + + template + void process(T& out, const StringData* name) { + write_raw(ser, size); + write_string(ser, name); + write_raw(ser, sym); + TargetProfile::reduce(out, handle, size); + if (size == sizeof(T)) { + write_maybe_serializable(ser, out); + } else { + write_raw(ser, &out, size); + } + } + + template void operator()(const T&) {} + template + void operator()(const rds::Profile& pt) { + if (size == sizeof(T)) { + T out{}; + process(out, pt.name.get()); + } else { + auto const mem = calloc(1, size); + SCOPE_EXIT { free(mem); }; + process(*reinterpret_cast(mem), pt.name.get()); + } + } + + ProfDataSerializer& ser; + const rds::Symbol& sym; + rds::Handle handle; + uint32_t size; +}; + +void write_target_profiles(ProfDataSerializer& ser) { + rds::visitSymbols( + [&] (const rds::Symbol& symbol, rds::Handle handle, uint32_t size) { + TargetProfileVisitor tv(ser, symbol, handle, size); + boost::apply_visitor(tv, symbol); + } + ); + write_raw(ser, uint32_t{}); +} + +template +auto read_impl(ProfDataDeserializer& ser, T& out, bool) -> + decltype(out.deserialize(ser),void()) { + out.deserialize(ser); +} + +template +void read_impl(ProfDataDeserializer& ser, T& out, int) { + read_raw(ser, out); +} + +template +void read_maybe_serializable(ProfDataDeserializer& ser, T& out) { + read_impl(ser, out, false); +} + +struct SymbolFixup : boost::static_visitor { + SymbolFixup(ProfDataDeserializer& ser, StringData* name, uint32_t size) : + ser{ser}, name{name}, size{size} {} + + template void operator()(T&) { always_assert(false); } + template + void operator()(rds::Profile& pt) { + TargetProfile prof(pt.transId, + TransKind::Profile, + pt.bcOff, + name, + size - sizeof(T)); + + if (size == sizeof(T)) { + read_maybe_serializable(ser, prof.value()); + } else { + read_raw(ser, &prof.value(), size); + } + } + + ProfDataDeserializer& ser; + StringData* name; + // The size of the original rds allocation. + uint32_t size; +}; + +void read_target_profiles(ProfDataDeserializer& ser) { + while (true) { + auto const size = read_raw(ser); + if (!size) break; + auto const name = read_string(ser); + auto sym = read_raw(ser); + auto sf = SymbolFixup{ser, name, size}; + boost::apply_visitor(sf, sym); + } +} + //////////////////////////////////////////////////////////////////////////////// } @@ -784,6 +913,8 @@ bool serializeProfData(const std::string& filename) { auto const pd = profData(); write_prof_data(ser, pd); + write_target_profiles(ser); + return true; } catch (std::runtime_error& err) { FTRACE(1, "serializeProfData - Failed: {}\n", err.what()); @@ -802,6 +933,8 @@ bool deserializeProfData(const std::string& filename) { read_prof_data(ser, pd); pd->setDeserialized(); + read_target_profiles(ser); + return true; } catch (std::runtime_error& err) { FTRACE(1, "deserializeProfData - Failed: {}\n", err.what()); diff --git a/hphp/runtime/vm/jit/target-profile.h b/hphp/runtime/vm/jit/target-profile.h index 07f47899538..1b32ad1c0dd 100644 --- a/hphp/runtime/vm/jit/target-profile.h +++ b/hphp/runtime/vm/jit/target-profile.h @@ -106,6 +106,15 @@ auto call_tostring(const T& t, uint64_t size) -> decltype(auto) { * example of a variably sized profiler). * * rds::Profile also needs to be added to rds::Symbol. + * + * If the MyType contains pointers, or other data that needs updating + * when serializing/deserializing, it should also define + * + * void MyType::serialize(ProfDataSerializer& ser, const T& t) const; + * void MyType::deserialize(ProfDataDeserializer& ser, T& t); + * + * Note that custom serialization/deserialization is currently not + * supported for variable sized profilers. */ template struct TargetProfile { @@ -187,7 +196,7 @@ struct TargetProfile { * if profiling(). */ rds::Handle handle() const { return m_link.handle(); } - + T& value() const { return *m_link; } private: static rds::Link createLink(TransID profTransID, TransKind kind, -- 2.11.4.GIT