Index: mojo/public/tests/system/core_perftest.cc |
diff --git a/mojo/public/tests/system/core_perftest.cc b/mojo/public/tests/system/core_perftest.cc |
index bfb8ff36a568adc3b6d2496ae9a99e2f00034bc6..6874375bdadb0fc046094894ab34318ef28263de 100644 |
--- a/mojo/public/tests/system/core_perftest.cc |
+++ b/mojo/public/tests/system/core_perftest.cc |
@@ -7,13 +7,112 @@ |
#include "mojo/public/system/core.h" |
#include <assert.h> |
+#include <stddef.h> |
+#include <stdint.h> |
+#include <stdio.h> |
#include "mojo/public/system/macros.h" |
+#include "mojo/public/tests/test_support.h" |
#include "mojo/public/tests/test_utils.h" |
#include "testing/gtest/include/gtest/gtest.h" |
+// TODO(vtl): (here and below) crbug.com/342893 |
+#if !defined(WIN32) |
+#include <time.h> |
+#include "mojo/public/utility/thread.h" |
+#endif // !defined(WIN32) |
+ |
namespace { |
+#if !defined(WIN32) |
+class MessagePipeWriterThread : public mojo::Thread { |
+ public: |
+ MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes) |
+ : handle_(handle), |
+ num_bytes_(num_bytes), |
+ num_writes_(0) {} |
+ virtual ~MessagePipeWriterThread() {} |
+ |
+ virtual void Run() MOJO_OVERRIDE { |
+ char buffer[10000]; |
+ assert(num_bytes_ <= sizeof(buffer)); |
+ |
+ // TODO(vtl): Should I throttle somehow? |
+ for (;;) { |
+ MojoResult result = MojoWriteMessage(handle_, buffer, num_bytes_, NULL, 0, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE); |
+ if (result == MOJO_RESULT_OK) { |
+ num_writes_++; |
+ continue; |
+ } |
+ |
+ // We failed to write. |
+ // Either |handle_| or its peer was closed. |
+ assert(result == MOJO_RESULT_INVALID_ARGUMENT || |
+ result == MOJO_RESULT_FAILED_PRECONDITION); |
+ break; |
+ } |
+ } |
+ |
+ // Use only after joining the thread. |
+ int64_t num_writes() const { return num_writes_; } |
+ |
+ private: |
+ const MojoHandle handle_; |
+ const uint32_t num_bytes_; |
+ int64_t num_writes_; |
+ |
+ MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread); |
+}; |
+ |
+class MessagePipeReaderThread : public mojo::Thread { |
+ public: |
+ explicit MessagePipeReaderThread(MojoHandle handle) |
+ : handle_(handle), |
+ num_reads_(0) { |
+ } |
+ virtual ~MessagePipeReaderThread() {} |
+ |
+ virtual void Run() MOJO_OVERRIDE { |
+ char buffer[10000]; |
+ |
+ for (;;) { |
+ uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); |
+ MojoResult result = MojoReadMessage(handle_, buffer, &num_bytes, NULL, |
+ NULL, MOJO_READ_MESSAGE_FLAG_NONE); |
+ if (result == MOJO_RESULT_OK) { |
+ num_reads_++; |
+ continue; |
+ } |
+ |
+ if (result == MOJO_RESULT_SHOULD_WAIT) { |
+ result = MojoWait(handle_, MOJO_WAIT_FLAG_READABLE, |
+ MOJO_DEADLINE_INDEFINITE); |
+ if (result == MOJO_RESULT_OK) { |
+ // Go to the top of the loop to read again. |
+ continue; |
+ } |
+ } |
+ |
+ // We failed to read and possibly failed to wait. |
+ // Either |handle_| or its peer was closed. |
+ assert(result == MOJO_RESULT_INVALID_ARGUMENT || |
+ result == MOJO_RESULT_FAILED_PRECONDITION); |
+ break; |
+ } |
+ } |
+ |
+ // Use only after joining the thread. |
+ int64_t num_reads() const { return num_reads_; } |
+ |
+ private: |
+ const MojoHandle handle_; |
+ int64_t num_reads_; |
+ |
+ MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread); |
+}; |
+#endif // !defined(WIN32) |
+ |
class CorePerftest : public testing::Test { |
public: |
CorePerftest() : buffer_(NULL), num_bytes_(0) {} |
@@ -60,6 +159,85 @@ class CorePerftest : public testing::Test { |
} |
protected: |
+#if !defined(WIN32) |
+ void DoMessagePipeThreadedTest(unsigned num_writers, |
+ unsigned num_readers, |
+ uint32_t num_bytes) { |
+ static const int64_t kPerftestTimeMicroseconds = 3 * 1000000; |
+ |
+ assert(num_writers > 0); |
+ assert(num_readers > 0); |
+ |
+ MojoResult result MOJO_ALLOW_UNUSED; |
+ result = MojoCreateMessagePipe(&h0_, &h1_); |
+ assert(result == MOJO_RESULT_OK); |
+ |
+ std::vector<MessagePipeWriterThread*> writers; |
+ for (unsigned i = 0; i < num_writers; i++) |
+ writers.push_back(new MessagePipeWriterThread(h0_, num_bytes)); |
+ |
+ std::vector<MessagePipeReaderThread*> readers; |
+ for (unsigned i = 0; i < num_readers; i++) |
+ readers.push_back(new MessagePipeReaderThread(h1_)); |
+ |
+ // Start time here, just before we fire off the threads. |
+ const MojoTimeTicks start_time = MojoGetTimeTicksNow(); |
+ |
+ // Interleave the starts. |
+ for (unsigned i = 0; i < num_writers || i < num_readers; i++) { |
+ if (i < num_writers) |
+ writers[i]->Start(); |
+ if (i < num_readers) |
+ readers[i]->Start(); |
+ } |
+ |
+ Sleep(kPerftestTimeMicroseconds); |
+ |
+ // Close both handles to make writers and readers stop immediately. |
+ result = MojoClose(h0_); |
+ assert(result == MOJO_RESULT_OK); |
+ result = MojoClose(h1_); |
+ assert(result == MOJO_RESULT_OK); |
+ |
+ // Join everything. |
+ for (unsigned i = 0; i < num_writers; i++) |
+ writers[i]->Join(); |
+ for (unsigned i = 0; i < num_readers; i++) |
+ readers[i]->Join(); |
+ |
+ // Stop time here. |
+ MojoTimeTicks end_time = MojoGetTimeTicksNow(); |
+ |
+ // Add up write and read counts, and destroy the threads. |
+ int64_t num_writes = 0; |
+ for (unsigned i = 0; i < num_writers; i++) { |
+ num_writes += writers[i]->num_writes(); |
+ delete writers[i]; |
+ } |
+ writers.clear(); |
+ int64_t num_reads = 0; |
+ for (unsigned i = 0; i < num_readers; i++) { |
+ num_reads += readers[i]->num_reads(); |
+ delete readers[i]; |
+ } |
+ readers.clear(); |
+ |
+ char test_name[200]; |
+ sprintf(test_name, "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes", |
+ num_writers, num_readers, static_cast<unsigned>(num_bytes)); |
+ mojo::test::LogPerfResult(test_name, |
+ 1000000.0 * static_cast<double>(num_writes) / |
+ (end_time - start_time), |
+ "writes/second"); |
+ sprintf(test_name, "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes", |
+ num_writers, num_readers, static_cast<unsigned>(num_bytes)); |
+ mojo::test::LogPerfResult(test_name, |
+ 1000000.0 * static_cast<double>(num_reads) / |
+ (end_time - start_time), |
+ "reads/second"); |
+ } |
+#endif // !defined(WIN32) |
+ |
MojoHandle h0_; |
MojoHandle h1_; |
@@ -67,6 +245,18 @@ class CorePerftest : public testing::Test { |
uint32_t num_bytes_; |
private: |
+#if !defined(WIN32) |
+ void Sleep(int64_t microseconds) { |
+ struct timespec req = { |
+ static_cast<time_t>(microseconds / 1000000), // Seconds. |
+ static_cast<long>(microseconds % 1000000) * 1000L // Nanoseconds. |
+ }; |
+ int rv MOJO_ALLOW_UNUSED; |
+ rv = nanosleep(&req, NULL); |
+ assert(rv == 0); |
+ } |
+#endif // !defined(WIN32) |
+ |
MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest); |
}; |
@@ -122,4 +312,26 @@ TEST_F(CorePerftest, MessagePipe_EmptyRead) { |
assert(result == MOJO_RESULT_OK); |
} |
+#if !defined(WIN32) |
+TEST_F(CorePerftest, MessagePipe_Threaded) { |
+ DoMessagePipeThreadedTest(1u, 1u, 100u); |
+ DoMessagePipeThreadedTest(2u, 2u, 100u); |
+ DoMessagePipeThreadedTest(3u, 3u, 100u); |
+ DoMessagePipeThreadedTest(10u, 10u, 100u); |
+ DoMessagePipeThreadedTest(10u, 1u, 100u); |
+ DoMessagePipeThreadedTest(1u, 10u, 100u); |
+ |
+ // For comparison of overhead: |
+ DoMessagePipeThreadedTest(1u, 1u, 10u); |
+ // 100 was done above. |
+ DoMessagePipeThreadedTest(1u, 1u, 1000u); |
+ DoMessagePipeThreadedTest(1u, 1u, 10000u); |
+ |
+ DoMessagePipeThreadedTest(3u, 3u, 10u); |
+ // 100 was done above. |
+ DoMessagePipeThreadedTest(3u, 3u, 1000u); |
+ DoMessagePipeThreadedTest(3u, 3u, 10000u); |
+} |
+#endif // !defined(WIN32) |
+ |
} // namespace |