diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 21:49:38 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 21:49:38 +0000 |
commit | d7cae12696b96500c05dd2d430f6238922c20c96 (patch) | |
tree | ecff27b367735535b2a66477f8cd89d3c462a6c0 /base/stats_table_unittest.cc | |
parent | ee2815e28d408216cf94e874825b6bcf76c69083 (diff) | |
download | chromium_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.cc | 396 |
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 |