Buffer pool: Add basic counters to buffer pool client

Change-Id: I9a5a57b7cfccf67ee498e68964f1e077075ee325
Reviewed-on: http://gerrit.cloudera.org:8080/4714
Reviewed-by: Tim Armstrong <tarmstr...@cloudera.com>
Tested-by: Internal Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/e3a08914
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/e3a08914
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/e3a08914

Branch: refs/heads/master
Commit: e3a08914451a63fe65e8f66afc743739f4570ba4
Parents: 07da767
Author: Tim Armstrong <tarmstr...@cloudera.com>
Authored: Fri Oct 7 09:23:59 2016 -0700
Committer: Internal Jenkins <cloudera-hud...@gerrit.cloudera.org>
Committed: Tue Oct 18 04:48:43 2016 +0000

----------------------------------------------------------------------
 be/src/bufferpool/buffer-pool-counters.h      | 47 ++++++++++++++++++++++
 be/src/bufferpool/buffer-pool-test.cc         | 30 +++++++-------
 be/src/bufferpool/buffer-pool.cc              | 33 ++++++++++++---
 be/src/bufferpool/buffer-pool.h               | 15 +++++--
 be/src/bufferpool/reservation-tracker-test.cc |  9 +----
 5 files changed, 102 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e3a08914/be/src/bufferpool/buffer-pool-counters.h
----------------------------------------------------------------------
diff --git a/be/src/bufferpool/buffer-pool-counters.h 
b/be/src/bufferpool/buffer-pool-counters.h
new file mode 100644
index 0000000..6f3801e
--- /dev/null
+++ b/be/src/bufferpool/buffer-pool-counters.h
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 IMPALA_BUFFER_POOL_COUNTERS_H
+#define IMPALA_BUFFER_POOL_COUNTERS_H
+
+#include "util/runtime-profile.h"
+
+namespace impala {
+
+/// A set of counters for each buffer pool client.
+struct BufferPoolClientCounters {
+ public:
+  /// Amount of time spent trying to get a buffer.
+  RuntimeProfile::Counter* get_buffer_time;
+
+  /// Amount of time spent waiting for reads from disk to complete.
+  RuntimeProfile::Counter* read_wait_time;
+
+  /// Amount of time spent waiting for writes to disk to complete.
+  RuntimeProfile::Counter* write_wait_time;
+
+  /// The peak total size of unpinned buffers.
+  RuntimeProfile::HighWaterMarkCounter* peak_unpinned_bytes;
+
+  /// The total bytes of data unpinned. Every time a page's pin count goes 
from 1 to 0,
+  /// this counter is incremented by the page size.
+  RuntimeProfile::Counter* total_unpinned_bytes;
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e3a08914/be/src/bufferpool/buffer-pool-test.cc
----------------------------------------------------------------------
diff --git a/be/src/bufferpool/buffer-pool-test.cc 
b/be/src/bufferpool/buffer-pool-test.cc
index 16cf12c..793bcb9 100644
--- a/be/src/bufferpool/buffer-pool-test.cc
+++ b/be/src/bufferpool/buffer-pool-test.cc
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <gtest/gtest.h>
 #include <boost/bind.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/thread/thread.hpp>
@@ -29,7 +28,7 @@
 #include "common/init.h"
 #include "common/object-pool.h"
 #include "testutil/death-test-util.h"
-#include "testutil/test-macros.h"
+#include "testutil/gtest-util.h"
 
 #include "common/names.h"
 
@@ -125,7 +124,8 @@ void BufferPoolTest::RegisterQueriesAndClients(BufferPool* 
pool, int query_id_hi
       EXPECT_TRUE(
           
client_reservations[i][j].IncreaseReservationToFit(initial_client_reservation));
       string name = Substitute("Client $0 for query $1", j, query_id);
-      EXPECT_OK(pool->RegisterClient(name, &client_reservations[i][j], 
&clients[i][j]));
+      EXPECT_OK(pool->RegisterClient(
+          name, &client_reservations[i][j], NewProfile(), &clients[i][j]));
     }
 
     for (int j = 0; j < clients_per_query; ++j) {
@@ -209,7 +209,7 @@ TEST_F(BufferPoolTest, PageCreation) {
   client_tracker->InitChildTracker(NewProfile(), &global_reservations_, NULL, 
total_mem);
   ASSERT_TRUE(client_tracker->IncreaseReservation(total_mem));
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", client_tracker, &client));
+  ASSERT_OK(pool.RegisterClient("test client", client_tracker, NewProfile(), 
&client));
 
   vector<BufferPool::PageHandle> handles(num_pages);
 
@@ -256,7 +256,7 @@ TEST_F(BufferPoolTest, BufferAllocation) {
   client_tracker->InitChildTracker(NewProfile(), &global_reservations_, NULL, 
total_mem);
   ASSERT_TRUE(client_tracker->IncreaseReservationToFit(total_mem));
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", client_tracker, &client));
+  ASSERT_OK(pool.RegisterClient("test client", client_tracker, NewProfile(), 
&client));
 
   vector<BufferPool::BufferHandle> handles(num_buffers);
 
@@ -302,7 +302,8 @@ TEST_F(BufferPoolTest, BufferTransfer) {
     client_trackers[i].InitChildTracker(
         NewProfile(), &global_reservations_, NULL, TEST_BUFFER_LEN);
     ASSERT_TRUE(client_trackers[i].IncreaseReservationToFit(TEST_BUFFER_LEN));
-    ASSERT_OK(pool.RegisterClient("test client", &client_trackers[i], 
&clients[i]));
+    ASSERT_OK(pool.RegisterClient(
+        "test client", &client_trackers[i], NewProfile(), &clients[i]));
   }
 
   // Transfer the page around between the clients repeatedly in a circle.
@@ -344,7 +345,7 @@ TEST_F(BufferPoolTest, Pin) {
       NewProfile(), &global_reservations_, NULL, child_reservation);
   ASSERT_TRUE(client_tracker->IncreaseReservationToFit(child_reservation));
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", client_tracker, &client));
+  ASSERT_OK(pool.RegisterClient("test client", client_tracker, NewProfile(), 
&client));
 
   BufferPool::PageHandle handle1, handle2;
 
@@ -395,7 +396,7 @@ TEST_F(BufferPoolTest, PinWithoutReservation) {
   client_tracker->InitChildTracker(
       NewProfile(), &global_reservations_, NULL, TEST_BUFFER_LEN);
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", client_tracker, &client));
+  ASSERT_OK(pool.RegisterClient("test client", client_tracker, NewProfile(), 
&client));
 
   BufferPool::PageHandle handle;
   IMPALA_ASSERT_DEBUG_DEATH(pool.CreatePage(&client, TEST_BUFFER_LEN, 
&handle), "");
@@ -423,7 +424,7 @@ TEST_F(BufferPoolTest, ExtractBuffer) {
       NewProfile(), &global_reservations_, NULL, child_reservation);
   ASSERT_TRUE(client_tracker->IncreaseReservationToFit(child_reservation));
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", client_tracker, &client));
+  ASSERT_OK(pool.RegisterClient("test client", client_tracker, NewProfile(), 
&client));
 
   BufferPool::PageHandle page;
   BufferPool::BufferHandle buffer;
@@ -499,7 +500,7 @@ void BufferPoolTest::CreatePageLoop(
   ReservationTracker client_tracker;
   client_tracker.InitChildTracker(NewProfile(), parent_tracker, NULL, 
TEST_BUFFER_LEN);
   BufferPool::Client client;
-  ASSERT_OK(pool->RegisterClient("test client", &client_tracker, &client));
+  ASSERT_OK(pool->RegisterClient("test client", &client_tracker, NewProfile(), 
&client));
   for (int i = 0; i < num_ops; ++i) {
     BufferPool::PageHandle handle;
     ASSERT_TRUE(client_tracker.IncreaseReservation(TEST_BUFFER_LEN));
@@ -525,7 +526,8 @@ TEST_F(BufferPoolTest, CapacityExhausted) {
   BufferPool::PageHandle handle1, handle2, handle3;
 
   BufferPool::Client client;
-  ASSERT_OK(pool.RegisterClient("test client", &global_reservations_, 
&client));
+  ASSERT_OK(
+      pool.RegisterClient("test client", &global_reservations_, NewProfile(), 
&client));
   ASSERT_TRUE(global_reservations_.IncreaseReservation(TEST_BUFFER_LEN));
   ASSERT_OK(pool.CreatePage(&client, TEST_BUFFER_LEN, &handle1));
 
@@ -549,8 +551,4 @@ TEST_F(BufferPoolTest, CapacityExhausted) {
 }
 }
 
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  impala::InitCommonRuntime(argc, argv, true, impala::TestInfo::BE_TEST);
-  return RUN_ALL_TESTS();
-}
+IMPALA_TEST_MAIN();

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e3a08914/be/src/bufferpool/buffer-pool.cc
----------------------------------------------------------------------
diff --git a/be/src/bufferpool/buffer-pool.cc b/be/src/bufferpool/buffer-pool.cc
index eaa4262..3035694 100644
--- a/be/src/bufferpool/buffer-pool.cc
+++ b/be/src/bufferpool/buffer-pool.cc
@@ -25,6 +25,7 @@
 #include "common/names.h"
 #include "gutil/strings/substitute.h"
 #include "util/bit-util.h"
+#include "util/runtime-profile-counters.h"
 #include "util/uid-util.h"
 
 namespace impala {
@@ -176,14 +177,26 @@ BufferPool::~BufferPool() {
 }
 
 Status BufferPool::RegisterClient(
-    const string& name, ReservationTracker* reservation, Client* client) {
+    const string& name, ReservationTracker* reservation, RuntimeProfile* 
profile,
+    Client* client) {
   DCHECK(!client->is_registered());
   DCHECK(reservation != NULL);
+  client->InitCounters(profile);
   client->reservation_ = reservation;
   client->name_ = name;
   return Status::OK();
 }
 
+void BufferPool::Client::InitCounters(RuntimeProfile* profile) {
+  counters_.get_buffer_time = ADD_TIMER(profile, "BufferPoolGetBufferTime");
+  counters_.read_wait_time = ADD_TIMER(profile, "BufferPoolReadWaitTime");
+  counters_.write_wait_time = ADD_TIMER(profile, "BufferPoolWriteWaitTime");
+  counters_.peak_unpinned_bytes =
+      profile->AddHighWaterMarkCounter("BufferPoolPeakUnpinnedBytes", 
TUnit::BYTES);
+  counters_.total_unpinned_bytes =
+      ADD_COUNTER(profile, "BufferPoolTotalUnpinnedBytes", TUnit::BYTES);
+}
+
 void BufferPool::DeregisterClient(Client* client) {
   if (!client->is_registered()) return;
   client->reservation_->Close();
@@ -256,13 +269,16 @@ Status BufferPool::Pin(Client* client, PageHandle* 
handle) {
   Page* page = handle->page_;
   {
     lock_guard<SpinLock> pl(page->lock); // Lock page while we work on its 
state.
-    if (!page->buffer.is_open()) {
-      // No changes have been made to state yet, so we can cleanly return on 
error.
-      RETURN_IF_ERROR(AllocateBufferInternal(client, page->len, 
&page->buffer));
+    if (page->pin_count == 0)  {
+      if (!page->buffer.is_open()) {
+        // No changes have been made to state yet, so we can cleanly return on 
error.
+        RETURN_IF_ERROR(AllocateBufferInternal(client, page->len, 
&page->buffer));
+
+        // TODO: will need to initiate/wait for read if the page is not 
in-memory.
+      }
+      COUNTER_ADD(client->counters_.peak_unpinned_bytes, -handle->len());
     }
     page->IncrementPinCount(handle);
-
-    // TODO: will need to initiate/wait for read if the page is not in-memory.
   }
 
   client->reservation_->AllocateFrom(page->len);
@@ -286,12 +302,16 @@ void BufferPool::UnpinLocked(Client* client, PageHandle* 
handle) {
   page->DecrementPinCount(handle);
   client->reservation_->ReleaseTo(page->len);
 
+  COUNTER_ADD(client->counters_.total_unpinned_bytes, handle->len());
+  COUNTER_ADD(client->counters_.peak_unpinned_bytes, handle->len());
+
   // TODO: can evict now. Only need to preserve contents if 'page->dirty' is 
true.
 }
 
 void BufferPool::ExtractBuffer(
     Client* client, PageHandle* page_handle, BufferHandle* buffer_handle) {
   DCHECK(page_handle->is_pinned());
+
   DCHECK_EQ(page_handle->client_, client);
 
   Page* page = page_handle->page_;
@@ -316,6 +336,7 @@ Status BufferPool::AllocateBufferInternal(
   DCHECK(!buffer->is_open());
   DCHECK_GE(len, min_buffer_len_);
   DCHECK_EQ(len, BitUtil::RoundUpToPowerOfTwo(len));
+  SCOPED_TIMER(client->counters_.get_buffer_time);
 
   // If there is headroom in 'buffer_bytes_remaining_', we can just allocate a 
new buffer.
   if (TryDecreaseBufferBytesRemaining(len)) {

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e3a08914/be/src/bufferpool/buffer-pool.h
----------------------------------------------------------------------
diff --git a/be/src/bufferpool/buffer-pool.h b/be/src/bufferpool/buffer-pool.h
index 44b5574..6a9641d 100644
--- a/be/src/bufferpool/buffer-pool.h
+++ b/be/src/bufferpool/buffer-pool.h
@@ -24,6 +24,7 @@
 #include <string>
 
 #include "bufferpool/buffer-allocator.h"
+#include "bufferpool/buffer-pool-counters.h"
 #include "common/atomic.h"
 #include "common/status.h"
 #include "gutil/macros.h"
@@ -167,10 +168,11 @@ class BufferPool {
 
   /// Register a client. Returns an error status and does not register the 
client if the
   /// arguments are invalid. 'name' is an arbitrary name used to identify the 
client in
-  /// any errors messages or logging. 'client' is the client to register. 
'client' should
-  /// not already be registered.
+  /// any errors messages or logging. Counters for this client are added to 
the (non-NULL)
+  /// 'profile'. 'client' is the client to register. 'client' should not 
already be
+  /// registered.
   Status RegisterClient(const std::string& name, ReservationTracker* 
reservation,
-      Client* client);
+      RuntimeProfile* profile, Client* client);
 
   /// Deregister 'client' if it is registered. Idempotent.
   void DeregisterClient(Client* client);
@@ -305,12 +307,19 @@ class BufferPool::Client {
   friend class BufferPool;
   DISALLOW_COPY_AND_ASSIGN(Client);
 
+  /// Initialize 'counters_' and add the counters to 'profile'.
+  void InitCounters(RuntimeProfile* profile);
+
   /// A name identifying the client.
   std::string name_;
 
   /// The reservation tracker for the client. NULL means the client isn't 
registered.
   /// All pages pinned by the client count as usage against 'reservation_'.
   ReservationTracker* reservation_;
+
+  /// The RuntimeProfile counters for this client. All non-NULL if 
is_registered()
+  /// is true.
+  BufferPoolClientCounters counters_;
 };
 
 /// A handle to a buffer allocated from the buffer pool. Each BufferHandle 
should only

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e3a08914/be/src/bufferpool/reservation-tracker-test.cc
----------------------------------------------------------------------
diff --git a/be/src/bufferpool/reservation-tracker-test.cc 
b/be/src/bufferpool/reservation-tracker-test.cc
index 93bf7b8..66ce287 100644
--- a/be/src/bufferpool/reservation-tracker-test.cc
+++ b/be/src/bufferpool/reservation-tracker-test.cc
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <gtest/gtest.h>
 #include <limits>
 #include <string>
 #include <vector>
@@ -24,7 +23,7 @@
 #include "common/init.h"
 #include "common/object-pool.h"
 #include "runtime/mem-tracker.h"
-#include "testutil/test-macros.h"
+#include "testutil/gtest-util.h"
 
 #include "common/names.h"
 
@@ -376,8 +375,4 @@ TEST_F(ReservationTrackerTest, 
MemTrackerIntegrationMultiLevel) {
 }
 }
 
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  impala::InitCommonRuntime(argc, argv, true, impala::TestInfo::BE_TEST);
-  return RUN_ALL_TESTS();
-}
+IMPALA_TEST_MAIN();

Reply via email to