This is an automated email from the ASF dual-hosted git repository.

todd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new ca64aa2  client: micro-optimizations to reduce CPU and allocations
ca64aa2 is described below

commit ca64aa2ed33c90d7a9d2d8552d6f060b596e9c3f
Author: Todd Lipcon <[email protected]>
AuthorDate: Tue Mar 3 13:55:54 2020 -0800

    client: micro-optimizations to reduce CPU and allocations
    
    Various small hot-spots I saw while profiling TSBS workloads which do a
    high number of very short scans:
    
    - replace vector<RemoteTabletServer> with boost's small_vector in spots
      in the client where we expect to usually have a very small number of
      qualifying servers.
    
    - Optimize ResourceMetrics to use a dense_hash_map instead of a
      std::map, which is more CPU efficient. Additionally, key the map based
      on StringPieces instead of std::strings, since in our use case we are
      always using strings with eternal lifetime (coming from the protobuf
      Descriptor) here.
    
    - Avoid creating a vector<FieldDescriptor*> when updating resource
      metrics. Instead iterate over the fields using index-based APIs that
      don't allocate.
    
    - Add a KuduSchema constructor taking a Schema rvalue-reference. This is
      called once per scan in when setting up ScanConfiguration.
    
    - Use make_shared for ColumnSchema shared_ptrs to avoid some atomic ops
    
    This cuts cycles used in tcmalloc in kudu-tsdbd for one workload by about
    11%.
    
    Change-Id: I705aef9f2e57d44f387b58650279130ff329666d
    Reviewed-on: http://gerrit.cloudera.org:8080/15439
    Reviewed-by: Adar Dembo <[email protected]>
    Tested-by: Todd Lipcon <[email protected]>
---
 src/kudu/client/client-internal.cc          |  7 +++++--
 src/kudu/client/resource_metrics-internal.h | 14 +++++++++++++-
 src/kudu/client/resource_metrics.cc         | 23 ++++++++++++++++++++---
 src/kudu/client/resource_metrics.h          |  8 ++++++++
 src/kudu/client/scanner-internal.cc         | 11 +++++++----
 src/kudu/client/schema.cc                   |  4 ++++
 src/kudu/client/schema.h                    |  3 +++
 src/kudu/common/schema.h                    |  4 ++--
 8 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/src/kudu/client/client-internal.cc 
b/src/kudu/client/client-internal.cc
index d74ea00..66de143 100644
--- a/src/kudu/client/client-internal.cc
+++ b/src/kudu/client/client-internal.cc
@@ -32,6 +32,8 @@
 #include <vector>
 
 #include <boost/bind.hpp> // IWYU pragma: keep
+#include <boost/container/small_vector.hpp>
+#include <boost/container/vector.hpp>
 #include <boost/function.hpp>
 #include <gflags/gflags_declare.h>
 #include <glog/logging.h>
@@ -74,6 +76,7 @@ DECLARE_int32(dns_resolver_max_threads_num);
 DECLARE_uint32(dns_resolver_cache_capacity_mb);
 DECLARE_uint32(dns_resolver_cache_ttl_sec);
 
+using boost::container::small_vector;
 using std::map;
 using std::pair;
 using std::set;
@@ -226,8 +229,8 @@ RemoteTabletServer* KuduClient::Data::SelectTServer(const 
scoped_refptr<RemoteTa
       // TODO(wdberkeley): Eventually, the client might use the hierarchical
       // structure of a location to determine proximity.
       const string client_location = location();
-      vector<RemoteTabletServer*> local;
-      vector<RemoteTabletServer*> same_location;
+      small_vector<RemoteTabletServer*, 1> local;
+      small_vector<RemoteTabletServer*, 3> same_location;
       local.reserve(filtered.size());
       same_location.reserve(filtered.size());
       for (RemoteTabletServer* rts : filtered) {
diff --git a/src/kudu/client/resource_metrics-internal.h 
b/src/kudu/client/resource_metrics-internal.h
index d9a522d..498e292 100644
--- a/src/kudu/client/resource_metrics-internal.h
+++ b/src/kudu/client/resource_metrics-internal.h
@@ -17,11 +17,17 @@
 #ifndef KUDU_CLIENT_RESOURCE_METRICS_INTERNAL_H
 #define KUDU_CLIENT_RESOURCE_METRICS_INTERNAL_H
 
+#include <list>
 #include <map>
 #include <mutex>
 #include <stdint.h>
+#include <set>
 #include <string>
 
+#include <sparsehash/dense_hash_map>
+
+#include "kudu/gutil/hash/hash.h"
+#include "kudu/gutil/strings/stringpiece.h"
 #include "kudu/util/locks.h"
 
 namespace kudu {
@@ -37,14 +43,20 @@ class ResourceMetrics::Data {
   std::map<std::string, int64_t> Get() const;
 
   // Increment the given counter.
+  ATTRIBUTE_DEPRECATED("Use StringPiece variant instead")
   void Increment(const std::string& name, int64_t amount);
 
+  // Increment the given counter. The memory referred to by 'name' must
+  // remain alive for the lifetime of this ResourceMetrics object.
+  void Increment(StringPiece name, int64_t amount);
+
   // Return metric's current value.
   int64_t GetMetric(const std::string& name) const;
 
  private:
   mutable simple_spinlock lock_;
-  std::map<std::string, int64_t> counters_;
+  google::dense_hash_map<StringPiece, int64_t, GoodFastHash<StringPiece>> 
counters_;
+  std::set<std::string> owned_strings_;
 };
 
 } // namespace client
diff --git a/src/kudu/client/resource_metrics.cc 
b/src/kudu/client/resource_metrics.cc
index c340fe6..9159679 100644
--- a/src/kudu/client/resource_metrics.cc
+++ b/src/kudu/client/resource_metrics.cc
@@ -16,13 +16,19 @@
 // under the License.
 
 #include "kudu/client/resource_metrics.h"
-#include "kudu/client/resource_metrics-internal.h"
 
+#include <cstdint>
 #include <map>
 #include <mutex>
+#include <set>
 #include <string>
+#include <utility>
+
+#include <sparsehash/dense_hash_map>
 
+#include "kudu/client/resource_metrics-internal.h"
 #include "kudu/gutil/map-util.h"
+#include "kudu/gutil/strings/stringpiece.h"
 
 namespace kudu {
 
@@ -49,18 +55,29 @@ int64_t ResourceMetrics::GetMetric(const std::string& name) 
const {
   return data_->GetMetric(name);
 }
 
-ResourceMetrics::Data::Data() {}
+ResourceMetrics::Data::Data() {
+  counters_.set_empty_key("");
+}
 
 ResourceMetrics::Data::~Data() {}
 
 void ResourceMetrics::Data::Increment(const std::string& name, int64_t amount) 
{
   std::lock_guard<simple_spinlock> l(lock_);
+  auto it = owned_strings_.insert(name).first;
+  counters_[*it] += amount;
+}
+void ResourceMetrics::Data::Increment(StringPiece name, int64_t amount) {
+  std::lock_guard<simple_spinlock> l(lock_);
   counters_[name] += amount;
 }
 
 std::map<std::string, int64_t> ResourceMetrics::Data::Get() const {
+  std::map<std::string, int64_t> ret;
   std::lock_guard<simple_spinlock> l(lock_);
-  return counters_;
+  for (const auto& p : counters_) {
+    ret.emplace(p.first.as_string(), p.second);
+  }
+  return ret;
 }
 
 int64_t ResourceMetrics::Data::GetMetric(const std::string& name) const {
diff --git a/src/kudu/client/resource_metrics.h 
b/src/kudu/client/resource_metrics.h
index 4f31ac4..015087d 100644
--- a/src/kudu/client/resource_metrics.h
+++ b/src/kudu/client/resource_metrics.h
@@ -26,6 +26,12 @@
 
 #include "kudu/util/kudu_export.h"
 
+#ifdef KUDU_HEADERS_NO_STUBS
+#include "kudu/gutil/port.h"
+#else
+#include "kudu/client/stubs.h"
+#endif
+
 namespace kudu {
 namespace client {
 
@@ -47,6 +53,7 @@ class KUDU_EXPORT ResourceMetrics {
   /// @param [in] amount
   ///   The amount to increment the metric
   ///   (negative @c amount corresponds to decrementing the metric).
+  ATTRIBUTE_DEPRECATED("This function will become private in a future 
release.")
   void Increment(const std::string& name, int64_t amount);
 
   /// Get current count for the specified metric.
@@ -57,6 +64,7 @@ class KUDU_EXPORT ResourceMetrics {
   int64_t GetMetric(const std::string& name) const;
 
  private:
+  friend class KuduScanner;
   class KUDU_NO_EXPORT Data;
   Data* data_;
 };
diff --git a/src/kudu/client/scanner-internal.cc 
b/src/kudu/client/scanner-internal.cc
index 717e5de..f552d4e 100644
--- a/src/kudu/client/scanner-internal.cc
+++ b/src/kudu/client/scanner-internal.cc
@@ -30,6 +30,7 @@
 
 #include "kudu/client/client-internal.h"
 #include "kudu/client/meta_cache.h"
+#include "kudu/client/resource_metrics-internal.h"
 #include "kudu/client/schema.h"
 #include "kudu/common/common.pb.h"
 #include "kudu/common/encoded_key.h"
@@ -38,6 +39,7 @@
 #include "kudu/common/schema.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/gutil/port.h"
+#include "kudu/gutil/strings/stringpiece.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rpc/connection.h"
 #include "kudu/rpc/rpc.h"
@@ -228,12 +230,13 @@ void KuduScanner::Data::UpdateResourceMetrics() {
   if (last_response_.has_resource_metrics()) {
     tserver::ResourceMetricsPB resource_metrics = 
last_response_.resource_metrics();
     const Reflection* reflection = resource_metrics.GetReflection();
-    vector<const FieldDescriptor*> fields;
-    reflection->ListFields(resource_metrics, &fields);
-    for (const FieldDescriptor* field : fields) {
+    const google::protobuf::Descriptor* desc = 
resource_metrics.GetDescriptor();
+    for (int i = 0; i < desc->field_count(); i++) {
+      const FieldDescriptor* field = desc->field(i);
       if (reflection->HasField(resource_metrics, field) &&
           field->cpp_type() == FieldDescriptor::CPPTYPE_INT64) {
-        resource_metrics_.Increment(field->name(), 
reflection->GetInt64(resource_metrics, field));
+        resource_metrics_.data_->Increment(StringPiece(field->name()),
+                                           
reflection->GetInt64(resource_metrics, field));
       }
     }
   }
diff --git a/src/kudu/client/schema.cc b/src/kudu/client/schema.cc
index 24cab91..9ac9f95 100644
--- a/src/kudu/client/schema.cc
+++ b/src/kudu/client/schema.cc
@@ -823,6 +823,10 @@ KuduSchema::KuduSchema(const Schema& schema)
   : schema_(new Schema(schema)) {
 }
 
+KuduSchema::KuduSchema(Schema&& schema)
+  : schema_(new Schema(schema)) {
+}
+
 KuduSchema::~KuduSchema() {
   delete schema_;
 }
diff --git a/src/kudu/client/schema.h b/src/kudu/client/schema.h
index eb0dcb1..08e9846 100644
--- a/src/kudu/client/schema.h
+++ b/src/kudu/client/schema.h
@@ -715,6 +715,9 @@ class KUDU_EXPORT KuduSchema {
 
   // For use by KuduSchema::FromSchema.
   explicit KuduSchema(const Schema& schema);
+#if __cplusplus >= 201103
+  explicit KuduSchema(Schema&& schema);
+#endif
 
   // Private since we don't want users to rely on the first N columns
   // being the keys.
diff --git a/src/kudu/common/schema.h b/src/kudu/common/schema.h
index 5c6fd16..ab19174 100644
--- a/src/kudu/common/schema.h
+++ b/src/kudu/common/schema.h
@@ -224,14 +224,14 @@ class ColumnSchema {
       : name_(std::move(name)),
         type_info_(GetTypeInfo(type)),
         is_nullable_(is_nullable),
-        read_default_(read_default ? new Variant(type, read_default) : 
nullptr),
+        read_default_(read_default ? std::make_shared<Variant>(type, 
read_default) : nullptr),
         attributes_(attributes),
         type_attributes_(type_attributes),
         comment_(std::move(comment)) {
     if (write_default == read_default) {
       write_default_ = read_default_;
     } else if (write_default != nullptr) {
-      write_default_.reset(new Variant(type, write_default));
+      write_default_ = std::make_shared<Variant>(type, write_default);
     }
   }
 

Reply via email to