summaryrefslogtreecommitdiffstats
path: root/base/stats_table_unittest.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
commitd7cae12696b96500c05dd2d430f6238922c20c96 (patch)
treeecff27b367735535b2a66477f8cd89d3c462a6c0 /base/stats_table_unittest.cc
parentee2815e28d408216cf94e874825b6bcf76c69083 (diff)
downloadchromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.zip
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.gz
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.bz2
Add base to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/stats_table_unittest.cc')
-rw-r--r--base/stats_table_unittest.cc396
1 files changed, 396 insertions, 0 deletions
diff --git a/base/stats_table_unittest.cc b/base/stats_table_unittest.cc
new file mode 100644
index 0000000..28527fc
--- /dev/null
+++ b/base/stats_table_unittest.cc
@@ -0,0 +1,396 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <process.h>
+#include <windows.h>
+
+#include "base/multiprocess_test.h"
+#include "base/stats_table.h"
+#include "base/stats_counters.h"
+#include "base/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ class StatsTableTest : public MultiProcessTest {
+ };
+}
+
+// Open a StatsTable and verify that we can write to each of the
+// locations in the table.
+TEST_F(StatsTableTest, VerifySlots) {
+ const std::wstring kTableName = L"VerifySlotsStatTable";
+ const int kMaxThreads = 1;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+
+ // Register a single thread.
+ std::wstring thread_name = L"mainThread";
+ int slot_id = table.RegisterThread(thread_name);
+ EXPECT_TRUE(slot_id);
+
+ // Fill up the table with counters.
+ std::wstring counter_base_name = L"counter";
+ for (int index=0; index < kMaxCounter; index++) {
+ std::wstring counter_name = counter_base_name;
+ StringAppendF(&counter_name, L"counter.ctr%d", index);
+ int counter_id = table.FindCounter(counter_name);
+ EXPECT_GT(counter_id, 0);
+ }
+
+ // Try to allocate an additional thread. Verify it fails.
+ slot_id = table.RegisterThread(L"too many threads");
+ EXPECT_EQ(slot_id, 0);
+
+ // Try to allocate an additional counter. Verify it fails.
+ int counter_id = table.FindCounter(counter_base_name);
+ EXPECT_EQ(counter_id, 0);
+}
+
+// CounterZero will continually be set to 0.
+const std::wstring kCounterZero = L"CounterZero";
+// Counter1313 will continually be set to 1313.
+const std::wstring kCounter1313 = L"Counter1313";
+// CounterIncrement will be incremented each time.
+const std::wstring kCounterIncrement = L"CounterIncrement";
+// CounterDecrement will be decremented each time.
+const std::wstring kCounterDecrement = L"CounterDecrement";
+// CounterMixed will be incremented by odd numbered threads and
+// decremented by even threads.
+const std::wstring kCounterMixed = L"CounterMixed";
+// The number of thread loops that we will do.
+const int kThreadLoops = 1000;
+
+unsigned __stdcall StatsTableMultipleThreadMain(void* param) {
+ // Each thread will open the shared memory and set counters
+ // concurrently in a loop. We'll use some pauses to
+ // mixup the thread scheduling.
+ int16 id = reinterpret_cast<int16>(param);
+
+ StatsCounter zero_counter(kCounterZero);
+ StatsCounter lucky13_counter(kCounter1313);
+ StatsCounter increment_counter(kCounterIncrement);
+ StatsCounter decrement_counter(kCounterDecrement);
+ for (int index = 0; index < kThreadLoops; index++) {
+ StatsCounter mixed_counter(kCounterMixed); // create this one in the loop
+ zero_counter.Set(0);
+ lucky13_counter.Set(1313);
+ increment_counter.Increment();
+ decrement_counter.Decrement();
+ if (id % 2)
+ mixed_counter.Decrement();
+ else
+ mixed_counter.Increment();
+ Sleep(index % 10); // short wait
+ }
+ return 0;
+}
+// Create a few threads and have them poke on their counters.
+TEST_F(StatsTableTest, MultipleThreads) {
+ // Create a stats table.
+ const std::wstring kTableName = L"MultipleThreadStatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ EXPECT_EQ(0, table.CountThreadsRegistered());
+
+ // Spin up a set of threads to go bang on the various counters.
+ // After we join the threads, we'll make sure the counters
+ // contain the values we expected.
+ HANDLE threads[kMaxThreads];
+
+ // Spawn the threads.
+ for (int16 index = 0; index < kMaxThreads; index++) {
+ void* argument = reinterpret_cast<void*>(index);
+ unsigned thread_id;
+ threads[index] = reinterpret_cast<HANDLE>(
+ _beginthreadex(NULL, 0, StatsTableMultipleThreadMain, argument, 0,
+ &thread_id));
+ EXPECT_NE((HANDLE)NULL, threads[index]);
+ }
+
+ // Wait for the threads to finish.
+ for (int index = 0; index < kMaxThreads; index++) {
+ DWORD rv = WaitForSingleObject(threads[index], 60 * 1000);
+ EXPECT_EQ(rv, WAIT_OBJECT_0); // verify all threads finished
+ }
+ StatsCounter zero_counter(kCounterZero);
+ StatsCounter lucky13_counter(kCounter1313);
+ StatsCounter increment_counter(kCounterIncrement);
+ StatsCounter decrement_counter(kCounterDecrement);
+ StatsCounter mixed_counter(kCounterMixed);
+
+ // Verify the various counters are correct.
+ std::wstring name;
+ name = L"c:" + kCounterZero;
+ EXPECT_EQ(0, table.GetCounterValue(name));
+ name = L"c:" + kCounter1313;
+ EXPECT_EQ(1313 * kMaxThreads,
+ table.GetCounterValue(name));
+ name = L"c:" + kCounterIncrement;
+ EXPECT_EQ(kMaxThreads * kThreadLoops,
+ table.GetCounterValue(name));
+ name = L"c:" + kCounterDecrement;
+ EXPECT_EQ(-kMaxThreads * kThreadLoops,
+ table.GetCounterValue(name));
+ name = L"c:" + kCounterMixed;
+ EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
+ table.GetCounterValue(name));
+ EXPECT_EQ(0, table.CountThreadsRegistered());
+}
+
+const std::wstring kTableName = L"MultipleProcessStatTable";
+
+extern "C" int __declspec(dllexport) ChildProcessMain() {
+ // Each process will open the shared memory and set counters
+ // concurrently in a loop. We'll use some pauses to
+ // mixup the scheduling.
+
+ StatsTable table(kTableName, 0, 0);
+ StatsTable::set_current(&table);
+ StatsCounter zero_counter(kCounterZero);
+ StatsCounter lucky13_counter(kCounter1313);
+ StatsCounter increment_counter(kCounterIncrement);
+ StatsCounter decrement_counter(kCounterDecrement);
+ for (int index = 0; index < kThreadLoops; index++) {
+ zero_counter.Set(0);
+ lucky13_counter.Set(1313);
+ increment_counter.Increment();
+ decrement_counter.Decrement();
+ Sleep(index % 10); // short wait
+ }
+ return 0;
+}
+
+// Create a few threads and have them poke on their counters.
+TEST_F(StatsTableTest, MultipleProcesses) {
+ // Create a stats table.
+ const std::wstring kTableName = L"MultipleProcessStatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ EXPECT_EQ(0, table.CountThreadsRegistered());
+
+ // Spin up a set of threads to go bang on the various counters.
+ // After we join the threads, we'll make sure the counters
+ // contain the values we expected.
+ HANDLE threads[kMaxThreads];
+
+ // Spawn the processes.
+ for (int16 index = 0; index < kMaxThreads; index++) {
+ threads[index] = this->SpawnChild(L"ChildProcessMain");
+ EXPECT_NE((HANDLE)NULL, threads[index]);
+ }
+
+ // Wait for the threads to finish.
+ for (int index = 0; index < kMaxThreads; index++) {
+ DWORD rv = WaitForSingleObject(threads[index], 60 * 1000);
+ EXPECT_EQ(rv, WAIT_OBJECT_0); // verify all threads finished
+ }
+ StatsCounter zero_counter(kCounterZero);
+ StatsCounter lucky13_counter(kCounter1313);
+ StatsCounter increment_counter(kCounterIncrement);
+ StatsCounter decrement_counter(kCounterDecrement);
+
+ // Verify the various counters are correct.
+ std::wstring name;
+ name = L"c:" + kCounterZero;
+ EXPECT_EQ(0, table.GetCounterValue(name));
+ name = L"c:" + kCounter1313;
+ EXPECT_EQ(1313 * kMaxThreads,
+ table.GetCounterValue(name));
+ name = L"c:" + kCounterIncrement;
+ EXPECT_EQ(kMaxThreads * kThreadLoops,
+ table.GetCounterValue(name));
+ name = L"c:" + kCounterDecrement;
+ EXPECT_EQ(-kMaxThreads * kThreadLoops,
+ table.GetCounterValue(name));
+ EXPECT_EQ(0, table.CountThreadsRegistered());
+}
+
+class MockStatsCounter : public StatsCounter {
+ public:
+ MockStatsCounter(const std::wstring& name)
+ : StatsCounter(name) {}
+ int* Pointer() { return GetPtr(); }
+};
+
+// Test some basic StatsCounter operations
+TEST_F(StatsTableTest, StatsCounter) {
+ // Create a stats table.
+ const std::wstring kTableName = L"StatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ MockStatsCounter foo(L"foo");
+
+ // Test initial state.
+ EXPECT_TRUE(foo.Enabled());
+ EXPECT_NE(foo.Pointer(), static_cast<int*>(0));
+ EXPECT_EQ(0, table.GetCounterValue(L"c:foo"));
+ EXPECT_EQ(0, *(foo.Pointer()));
+
+ // Test Increment.
+ while(*(foo.Pointer()) < 123) foo.Increment();
+ EXPECT_EQ(123, table.GetCounterValue(L"c:foo"));
+ foo.Add(0);
+ EXPECT_EQ(123, table.GetCounterValue(L"c:foo"));
+ foo.Add(-1);
+ EXPECT_EQ(122, table.GetCounterValue(L"c:foo"));
+
+ // Test Set.
+ foo.Set(0);
+ EXPECT_EQ(0, table.GetCounterValue(L"c:foo"));
+ foo.Set(100);
+ EXPECT_EQ(100, table.GetCounterValue(L"c:foo"));
+ foo.Set(-1);
+ EXPECT_EQ(-1, table.GetCounterValue(L"c:foo"));
+ foo.Set(0);
+ EXPECT_EQ(0, table.GetCounterValue(L"c:foo"));
+
+ // Test Decrement.
+ foo.Decrement(1);
+ EXPECT_EQ(-1, table.GetCounterValue(L"c:foo"));
+ foo.Decrement(0);
+ EXPECT_EQ(-1, table.GetCounterValue(L"c:foo"));
+ foo.Decrement(-1);
+ EXPECT_EQ(0, table.GetCounterValue(L"c:foo"));
+}
+
+class MockStatsCounterTimer : public StatsCounterTimer {
+ public:
+ MockStatsCounterTimer(const std::wstring& name)
+ : StatsCounterTimer(name) {}
+
+ TimeTicks start_time() { return start_time_; }
+ TimeTicks stop_time() { return stop_time_; }
+};
+
+// Test some basic StatsCounterTimer operations
+TEST_F(StatsTableTest, StatsCounterTimer) {
+ // Create a stats table.
+ const std::wstring kTableName = L"StatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ MockStatsCounterTimer bar(L"bar");
+
+ // Test initial state.
+ EXPECT_FALSE(bar.Running());
+ EXPECT_TRUE(bar.start_time().is_null());
+ EXPECT_TRUE(bar.stop_time().is_null());
+
+ // Do some timing.
+ bar.Start();
+ Sleep(500);
+ bar.Stop();
+ EXPECT_LE(500, table.GetCounterValue(L"t:bar"));
+
+ // Verify that timing again is additive.
+ bar.Start();
+ Sleep(500);
+ bar.Stop();
+ EXPECT_LE(1000, table.GetCounterValue(L"t:bar"));
+}
+
+// Test some basic StatsRate operations
+TEST_F(StatsTableTest, StatsRate) {
+ // Create a stats table.
+ const std::wstring kTableName = L"StatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ StatsRate baz(L"baz");
+
+ // Test initial state.
+ EXPECT_FALSE(baz.Running());
+ EXPECT_EQ(0, table.GetCounterValue(L"c:baz"));
+ EXPECT_EQ(0, table.GetCounterValue(L"t:baz"));
+
+ // Do some timing.
+ baz.Start();
+ Sleep(500);
+ baz.Stop();
+ EXPECT_EQ(1, table.GetCounterValue(L"c:baz"));
+ EXPECT_LE(500, table.GetCounterValue(L"t:baz"));
+
+ // Verify that timing again is additive.
+ baz.Start();
+ Sleep(500);
+ baz.Stop();
+ EXPECT_EQ(2, table.GetCounterValue(L"c:baz"));
+ EXPECT_LE(1000, table.GetCounterValue(L"t:baz"));
+}
+
+// Test some basic StatsScope operations
+TEST_F(StatsTableTest, StatsScope) {
+ // Create a stats table.
+ const std::wstring kTableName = L"StatTable";
+ const int kMaxThreads = 20;
+ const int kMaxCounter = 5;
+ StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+ StatsTable::set_current(&table);
+
+ StatsCounterTimer foo(L"foo");
+ StatsRate bar(L"bar");
+
+ // Test initial state.
+ EXPECT_EQ(0, table.GetCounterValue(L"t:foo"));
+ EXPECT_EQ(0, table.GetCounterValue(L"t:bar"));
+ EXPECT_EQ(0, table.GetCounterValue(L"c:bar"));
+
+ // Try a scope.
+ {
+ StatsScope<StatsCounterTimer> timer(foo);
+ StatsScope<StatsRate> timer2(bar);
+ Sleep(500);
+ }
+ EXPECT_LE(500, table.GetCounterValue(L"t:foo"));
+ EXPECT_LE(500, table.GetCounterValue(L"t:bar"));
+ EXPECT_EQ(1, table.GetCounterValue(L"c:bar"));
+
+ // Try a second scope.
+ {
+ StatsScope<StatsCounterTimer> timer(foo);
+ StatsScope<StatsRate> timer2(bar);
+ Sleep(500);
+ }
+ EXPECT_LE(1000, table.GetCounterValue(L"t:foo"));
+ EXPECT_LE(1000, table.GetCounterValue(L"t:bar"));
+ EXPECT_EQ(2, table.GetCounterValue(L"c:bar"));
+} \ No newline at end of file