From 5784c0d473f364f5860a1a8df60098ed43f3ddc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A1nos=20Benjamin=20Antal?= <benjamin.antal@memgraph.io>
Date: Tue, 25 Oct 2022 15:26:42 +0200
Subject: [PATCH] Return the custom data for profile queries

---
 src/query/v2/interpreter.cpp  |  2 +-
 src/query/v2/plan/profile.cpp | 65 ++++++++++++++++++++++++-----------
 src/query/v2/plan/profile.hpp |  2 ++
 3 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/src/query/v2/interpreter.cpp b/src/query/v2/interpreter.cpp
index 0fd11fdde..f82d5ee01 100644
--- a/src/query/v2/interpreter.cpp
+++ b/src/query/v2/interpreter.cpp
@@ -1040,7 +1040,7 @@ PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_tra
   auto rw_type_checker = plan::ReadWriteTypeChecker();
   rw_type_checker.InferRWType(const_cast<plan::LogicalOperator &>(cypher_query_plan->plan()));
 
-  return PreparedQuery{{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"},
+  return PreparedQuery{{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME", "CUSTOM DATA"},
                        std::move(parsed_query.required_privileges),
                        [plan = std::move(cypher_query_plan), parameters = std::move(parsed_inner_query.parameters),
                         summary, dba, interpreter_context, execution_memory, memory_limit, shard_request_manager,
diff --git a/src/query/v2/plan/profile.cpp b/src/query/v2/plan/profile.cpp
index 26c5280d4..3bd0953ba 100644
--- a/src/query/v2/plan/profile.cpp
+++ b/src/query/v2/plan/profile.cpp
@@ -24,18 +24,17 @@ namespace memgraph::query::v2::plan {
 
 namespace {
 
-unsigned long long IndividualCycles(const ProfilingStats &cumulative_stats) {
+uint64_t IndividualCycles(const ProfilingStats &cumulative_stats) {
   return cumulative_stats.num_cycles - std::accumulate(cumulative_stats.children.begin(),
                                                        cumulative_stats.children.end(), 0ULL,
                                                        [](auto acc, auto &stats) { return acc + stats.num_cycles; });
 }
 
-double RelativeTime(unsigned long long num_cycles, unsigned long long total_cycles) {
-  return static_cast<double>(num_cycles) / total_cycles;
+double RelativeTime(uint64_t num_cycles, uint64_t total_cycles) {
+  return static_cast<double>(num_cycles) / static_cast<double>(total_cycles);
 }
 
-double AbsoluteTime(unsigned long long num_cycles, unsigned long long total_cycles,
-                    std::chrono::duration<double> total_time) {
+double AbsoluteTime(uint64_t num_cycles, uint64_t total_cycles, std::chrono::duration<double> total_time) {
   return (RelativeTime(num_cycles, total_cycles) * static_cast<std::chrono::duration<double, std::milli>>(total_time))
       .count();
 }
@@ -50,26 +49,29 @@ namespace {
 
 class ProfilingStatsToTableHelper {
  public:
-  ProfilingStatsToTableHelper(unsigned long long total_cycles, std::chrono::duration<double> total_time)
+  ProfilingStatsToTableHelper(uint64_t total_cycles, std::chrono::duration<double> total_time)
       : total_cycles_(total_cycles), total_time_(total_time) {}
 
   void Output(const ProfilingStats &cumulative_stats) {
     auto cycles = IndividualCycles(cumulative_stats);
+    auto custom_data_copy = cumulative_stats.custom_data;
+    ConvertCyclesToTime(custom_data_copy);
 
-    rows_.emplace_back(std::vector<TypedValue>{
-        TypedValue(FormatOperator(cumulative_stats.name)), TypedValue(cumulative_stats.actual_hits),
-        TypedValue(FormatRelativeTime(cycles)), TypedValue(FormatAbsoluteTime(cycles))});
+    rows_.emplace_back(
+        std::vector<TypedValue>{TypedValue(FormatOperator(cumulative_stats.name)),
+                                TypedValue(cumulative_stats.actual_hits), TypedValue(FormatRelativeTime(cycles)),
+                                TypedValue(FormatAbsoluteTime(cycles)), TypedValue(custom_data_copy.dump())});
 
     for (size_t i = 1; i < cumulative_stats.children.size(); ++i) {
       Branch(cumulative_stats.children[i]);
     }
 
-    if (cumulative_stats.children.size() >= 1) {
+    if (!cumulative_stats.children.empty()) {
       Output(cumulative_stats.children[0]);
     }
   }
 
-  std::vector<std::vector<TypedValue>> rows() { return rows_; }
+  std::vector<std::vector<TypedValue>> rows() const { return rows_; }
 
  private:
   void Branch(const ProfilingStats &cumulative_stats) {
@@ -80,7 +82,28 @@ class ProfilingStatsToTableHelper {
     --depth_;
   }
 
-  std::string Format(const char *str) {
+  double AbsoluteTime(const uint64_t cycles) const { return plan::AbsoluteTime(cycles, total_cycles_, total_time_); }
+
+  double RelativeTime(const uint64_t cycles) const { return plan::RelativeTime(cycles, total_cycles_); }
+
+  void ConvertCyclesToTime(nlohmann::json &custom_data) const {
+    const auto convert_cycles_in_json = [this](nlohmann::json &json) {
+      if (!json.is_object()) {
+        return;
+      }
+      if (auto it = json.find(ProfilingStats::kNumCycles); it != json.end()) {
+        auto num_cycles = it.value().get<uint64_t>();
+        json[ProfilingStats::kAbsoluteTime] = AbsoluteTime(num_cycles);
+        json[ProfilingStats::kRelativeTime] = RelativeTime(num_cycles);
+      }
+    };
+
+    for (auto &json : custom_data) {
+      convert_cycles_in_json(json);
+    }
+  }
+
+  std::string Format(const char *str) const {
     std::ostringstream ss;
     for (int64_t i = 0; i < depth_; ++i) {
       ss << "| ";
@@ -89,21 +112,21 @@ class ProfilingStatsToTableHelper {
     return ss.str();
   }
 
-  std::string Format(const std::string &str) { return Format(str.c_str()); }
+  std::string Format(const std::string &str) const { return Format(str.c_str()); }
 
-  std::string FormatOperator(const char *str) { return Format(std::string("* ") + str); }
+  std::string FormatOperator(const char *str) const { return Format(std::string("* ") + str); }
 
-  std::string FormatRelativeTime(unsigned long long num_cycles) {
-    return fmt::format("{: 10.6f} %", RelativeTime(num_cycles, total_cycles_) * 100);
+  std::string FormatRelativeTime(uint64_t num_cycles) const {
+    return fmt::format("{: 10.6f} %", RelativeTime(num_cycles) * 100);
   }
 
-  std::string FormatAbsoluteTime(unsigned long long num_cycles) {
-    return fmt::format("{: 10.6f} ms", AbsoluteTime(num_cycles, total_cycles_, total_time_));
+  std::string FormatAbsoluteTime(uint64_t num_cycles) const {
+    return fmt::format("{: 10.6f} ms", AbsoluteTime(num_cycles));
   }
 
   int64_t depth_{0};
   std::vector<std::vector<TypedValue>> rows_;
-  unsigned long long total_cycles_;
+  uint64_t total_cycles_;
   std::chrono::duration<double> total_time_;
 };
 
@@ -126,7 +149,7 @@ class ProfilingStatsToJsonHelper {
   using json = nlohmann::json;
 
  public:
-  ProfilingStatsToJsonHelper(unsigned long long total_cycles, std::chrono::duration<double> total_time)
+  ProfilingStatsToJsonHelper(uint64_t total_cycles, std::chrono::duration<double> total_time)
       : total_cycles_(total_cycles), total_time_(total_time) {}
 
   void Output(const ProfilingStats &cumulative_stats) { return Output(cumulative_stats, &json_); }
@@ -151,7 +174,7 @@ class ProfilingStatsToJsonHelper {
   }
 
   json json_;
-  unsigned long long total_cycles_;
+  uint64_t total_cycles_;
   std::chrono::duration<double> total_time_;
 };
 
diff --git a/src/query/v2/plan/profile.hpp b/src/query/v2/plan/profile.hpp
index c18ae1e56..da25be33c 100644
--- a/src/query/v2/plan/profile.hpp
+++ b/src/query/v2/plan/profile.hpp
@@ -27,6 +27,8 @@ namespace plan {
  */
 struct ProfilingStats {
   static constexpr std::string_view kNumCycles{"num_cycles"};
+  static constexpr std::string_view kRelativeTime{"relative_time"};
+  static constexpr std::string_view kAbsoluteTime{"absolute_time"};
 
   int64_t actual_hits{0};
   uint64_t num_cycles{0};