http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/97d8dca8/utility/EventProfiler.hpp ---------------------------------------------------------------------- diff --git a/utility/EventProfiler.hpp b/utility/EventProfiler.hpp new file mode 100644 index 0000000..70024e6 --- /dev/null +++ b/utility/EventProfiler.hpp @@ -0,0 +1,188 @@ +/** + * Copyright 2016, Quickstep Research Group, Computer Sciences Department, + * University of WisconsinâMadison. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#ifndef QUICKSTEP_UTILITY_EVENT_PROFILER_HPP_ +#define QUICKSTEP_UTILITY_EVENT_PROFILER_HPP_ + +#include <chrono> +#include <cstddef> +#include <cstring> +#include <ctime> +#include <iomanip> +#include <map> +#include <ostream> +#include <thread> +#include <type_traits> +#include <utility> +#include <vector> + +#include "threading/Mutex.hpp" + +#include "glog/logging.h" + +namespace quickstep { + +/** \addtogroup Utility + * @{ + */ + +using clock = std::chrono::steady_clock; + +template <typename TagT, typename ...PayloadT> +class EventProfiler { + + public: + EventProfiler() + : zero_time_(clock::now()) { + } + + struct EventInfo { + clock::time_point start_time; + clock::time_point end_time; + bool is_finished; + std::tuple<PayloadT...> payload; + + explicit EventInfo(const clock::time_point &start_time_in) + : start_time(start_time_in), + is_finished(false) { + } + + EventInfo() + : start_time(clock::now()), + is_finished(false) { + } + + inline void setPayload(PayloadT &&...in_payload) { + payload = std::make_tuple(in_payload...); + } + + inline void endEvent() { + end_time = clock::now(); + is_finished = true; + } + }; + + struct EventContainer { + EventContainer() + : context(0) {} + + inline void startEvent(const TagT &tag) { + events[tag].emplace_back(clock::now()); + } + + inline void endEvent(const TagT &tag) { + auto &event_info = events.at(tag).back(); + event_info.is_finished = true; + event_info.end_time = clock::now(); + } + + inline std::vector<EventInfo> *getEventLine(const TagT &tag) { + return &events[tag]; + } + + inline void setContext(int context_in) { + context = context_in; + } + + inline int getContext() const { + return context; + } + + std::map<TagT, std::vector<EventInfo>> events; + int context; + }; + + EventContainer *getContainer() { + MutexLock lock(mutex_); + return &thread_map_[std::this_thread::get_id()]; + } + + void writeToStream(std::ostream &os) const { + time_t rawtime; + time(&rawtime); + char event_id[32]; + strftime(event_id, sizeof event_id, "%Y-%m-%d %H:%M:%S", localtime(&rawtime)); + + int thread_id = 0; + for (const auto &thread_ctx : thread_map_) { + for (const auto &event_group : thread_ctx.second.events) { + for (const auto &event_info : event_group.second) { + CHECK(event_info.is_finished) << "Unfinished profiling event"; + + os << std::setprecision(12) + << event_id << "," + << thread_id << "," << event_group.first << ","; + + PrintTuple(os, event_info.payload, ","); + + os << std::chrono::duration<double>(event_info.start_time - zero_time_).count() + << "," + << std::chrono::duration<double>(event_info.end_time - zero_time_).count() + << "\n"; + } + } + ++thread_id; + } + } + + void clear() { + zero_time_ = clock::now(); + thread_map_.clear(); + } + + const std::map<std::thread::id, EventContainer> &containers() { + return thread_map_; + } + + const clock::time_point &zero_time() { + return zero_time_; + } + + private: + template<class Tuple, std::size_t N> + struct TuplePrinter { + static void Print(std::ostream &os, const Tuple &t, const std::string &sep) { + TuplePrinter<Tuple, N-1>::Print(os, t, sep); + os << std::get<N-1>(t) << sep; + } + }; + + template<class Tuple> + struct TuplePrinter<Tuple, 1> { + static void Print(std::ostream &os, const Tuple &t, const std::string &sep) { + os << std::get<0>(t) << sep; + } + }; + + template<class... Args> + static void PrintTuple(std::ostream &os, const std::tuple<Args...>& t, const std::string &sep) { + TuplePrinter<decltype(t), sizeof...(Args)>::Print(os, t, sep); + } + + clock::time_point zero_time_; + std::map<std::thread::id, EventContainer> thread_map_; + Mutex mutex_; +}; + +extern EventProfiler<int, std::size_t> simple_profiler; +extern EventProfiler<std::size_t> relop_profiler; + +/** @} */ + +} // namespace quickstep + +#endif // QUICKSTEP_UTILITY_EVENT_PROFILER_HPP_
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/97d8dca8/utility/PlanVisualizer.cpp ---------------------------------------------------------------------- diff --git a/utility/PlanVisualizer.cpp b/utility/PlanVisualizer.cpp index 962d577..4cc1b0f 100644 --- a/utility/PlanVisualizer.cpp +++ b/utility/PlanVisualizer.cpp @@ -19,6 +19,7 @@ #include <cstddef> #include <memory> +#include <set> #include <sstream> #include <string> #include <unordered_map> @@ -28,6 +29,7 @@ #include "query_optimizer/cost_model/StarSchemaSimpleCostModel.hpp" #include "query_optimizer/expressions/AttributeReference.hpp" +#include "query_optimizer/physical/Aggregate.hpp" #include "query_optimizer/physical/HashJoin.hpp" #include "query_optimizer/physical/Physical.hpp" #include "query_optimizer/physical/PhysicalType.hpp" @@ -101,6 +103,10 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) { int node_id = ++id_counter_; node_id_map_.emplace(input, node_id); + std::set<E::ExprId> referenced_ids; + for (const auto &attr : input->getReferencedAttributes()) { + referenced_ids.emplace(attr->id()); + } for (const auto &child : input->children()) { visit(child); @@ -111,10 +117,8 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) { edge_info.src_node_id = child_id; edge_info.dst_node_id = node_id; - // Print output attributes except for TableReference -- there are just too many - // attributes out of TableReference. - if (child->getPhysicalType() != P::PhysicalType::kTableReference) { - for (const auto &attr : child->getOutputAttributes()) { + for (const auto &attr : child->getOutputAttributes()) { + if (referenced_ids.find(attr->id()) != referenced_ids.end()) { edge_info.labels.emplace_back(attr->attribute_alias()); } } @@ -145,6 +149,36 @@ void PlanVisualizer::visit(const P::PhysicalPtr &input) { node_info.labels.emplace_back( left_attributes[i]->attribute_alias() + " = " + right_attributes[i]->attribute_alias()); } + if (hash_join->left()->impliesUniqueAttributes(left_attributes)) { + node_info.labels.emplace_back("LEFT join attrs unique"); + } + if (hash_join->right()->impliesUniqueAttributes(right_attributes)) { + node_info.labels.emplace_back("RIGHT join attrs unique"); + } + + const auto &bf_config = hash_join->bloom_filter_config(); + for (const auto &bf : bf_config.build_side_bloom_filters) { + node_info.labels.emplace_back( + std::string("[BF build] ") + bf.attribute->attribute_alias()); + } + for (const auto &bf : bf_config.probe_side_bloom_filters) { + node_info.labels.emplace_back( + std::string("[BF probe] ") + bf.attribute->attribute_alias()); + } + + break; + } + case P::PhysicalType::kAggregate: { + const P::AggregatePtr aggregate = + std::static_pointer_cast<const P::Aggregate>(input); + node_info.labels.emplace_back(input->getName()); + + const auto &bf_config = aggregate->bloom_filter_config(); + for (const auto &bf : bf_config.probe_side_bloom_filters) { + node_info.labels.emplace_back( + std::string("[BF probe] ") + bf.attribute->attribute_alias()); + } + break; } default: {