#include "TestLatency.h" #include "IPDLUnitTests.h" // fail etc. // A ping/pong trial takes O(100us) or more, so if we don't have 10us // resolution or better, the results will not be terribly useful static const double kTimingResolutionCutoff = 0.00001; // 10us namespace mozilla { namespace _ipdltest { //----------------------------------------------------------------------------- // parent TestLatencyParent::TestLatencyParent() : mStart(), mPPTimeTotal(), mPP5TimeTotal(), mRpcTimeTotal(), mPPTrialsToGo(NR_TRIALS), mPP5TrialsToGo(NR_TRIALS), mNumChildProcessedCompressedSpams(0), mWhichPong5(0) { MOZ_COUNT_CTOR(TestLatencyParent); } TestLatencyParent::~TestLatencyParent() { MOZ_COUNT_DTOR(TestLatencyParent); } void TestLatencyParent::Main() { TimeDuration resolution = TimeDuration::Resolution(); if (resolution.ToSeconds() > kTimingResolutionCutoff) { puts(" (skipping TestLatency, timing resolution is too poor)"); Close(); return; } printf(" timing resolution: %g seconds\n", resolution.ToSecondsSigDigits()); if (mozilla::ipc::LoggingEnabled()) MOZ_CRASH( "you really don't want to log all IPC messages during this test, trust " "me"); PingPongTrial(); } void TestLatencyParent::PingPongTrial() { mStart = TimeStamp::Now(); if (!SendPing()) fail("sending Ping()"); } void TestLatencyParent::Ping5Pong5Trial() { mStart = TimeStamp::Now(); if (!SendPing5() || !SendPing5() || !SendPing5() || !SendPing5() || !SendPing5()) fail("sending Ping5()"); } mozilla::ipc::IPCResult TestLatencyParent::RecvPong() { TimeDuration thisTrial = (TimeStamp::Now() - mStart); mPPTimeTotal += thisTrial; if (0 == (mPPTrialsToGo % 1000)) printf(" PP trial %d: %g\n", mPPTrialsToGo, thisTrial.ToSecondsSigDigits()); if (--mPPTrialsToGo > 0) PingPongTrial(); else Ping5Pong5Trial(); return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyParent::RecvPong5() { ++mWhichPong5; if (mWhichPong5 < 5) { return IPC_OK(); } mWhichPong5 = 0; TimeDuration thisTrial = (TimeStamp::Now() - mStart); mPP5TimeTotal += thisTrial; if (0 == (mPP5TrialsToGo % 1000)) printf(" PP5 trial %d: %g\n", mPP5TrialsToGo, thisTrial.ToSecondsSigDigits()); if (0 < --mPP5TrialsToGo) Ping5Pong5Trial(); else RpcTrials(); return IPC_OK(); } void TestLatencyParent::RpcTrials() { TimeStamp start = TimeStamp::Now(); for (int i = 0; i < NR_TRIALS; ++i) { if (!CallRpc()) fail("can't call Rpc()"); if (0 == (i % 1000)) printf(" Rpc trial %d\n", i); } mRpcTimeTotal = (TimeStamp::Now() - start); SpamTrial(); } void TestLatencyParent::SpamTrial() { TimeStamp start = TimeStamp::Now(); for (int i = 0; i < NR_SPAMS - 1; ++i) { if (!SendSpam()) fail("sending Spam()"); if (0 == (i % 10000)) printf(" Spam trial %d\n", i); } // Synchronize with the child process to ensure all messages have // been processed. This adds the overhead of a reply message from // child-->here, but should be insignificant compared to >> // NR_SPAMS. if (!CallSynchro()) fail("calling Synchro()"); mSpamTimeTotal = (TimeStamp::Now() - start); CompressedSpamTrial(); } void TestLatencyParent::CompressedSpamTrial() { for (int i = 0; i < NR_SPAMS; ++i) { if (!SendCompressedSpam(i + 1)) fail("sending CompressedSpam()"); if (0 == (i % 10000)) printf(" CompressedSpam trial %d\n", i); } uint32_t lastSeqno; if (!CallSynchro2(&lastSeqno, &mNumChildProcessedCompressedSpams)) fail("calling Synchro2()"); if (lastSeqno != NR_SPAMS) fail("last seqno was %u, expected %u", lastSeqno, NR_SPAMS); // NB: since this is testing an optimization, it's somewhat bogus. // Need to make a warning if it actually intermittently fails in // practice, which is doubtful. if (!(mNumChildProcessedCompressedSpams < NR_SPAMS)) fail("Didn't compress any messages?"); Exit(); } void TestLatencyParent::Exit() { Close(); } //----------------------------------------------------------------------------- // child TestLatencyChild::TestLatencyChild() : mLastSeqno(0), mNumProcessedCompressedSpams(0), mWhichPing5(0) { MOZ_COUNT_CTOR(TestLatencyChild); } TestLatencyChild::~TestLatencyChild() { MOZ_COUNT_DTOR(TestLatencyChild); } mozilla::ipc::IPCResult TestLatencyChild::RecvPing() { SendPong(); return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::RecvPing5() { ++mWhichPing5; if (mWhichPing5 < 5) { return IPC_OK(); } mWhichPing5 = 0; if (!SendPong5() || !SendPong5() || !SendPong5() || !SendPong5() || !SendPong5()) fail("sending Pong5()"); return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::AnswerRpc() { return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::RecvSpam() { // no-op return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro() { return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::RecvCompressedSpam( const uint32_t& seqno) { if (seqno <= mLastSeqno) fail("compressed seqnos must monotonically increase"); mLastSeqno = seqno; ++mNumProcessedCompressedSpams; return IPC_OK(); } mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro2( uint32_t* lastSeqno, uint32_t* numMessagesDispatched) { *lastSeqno = mLastSeqno; *numMessagesDispatched = mNumProcessedCompressedSpams; return IPC_OK(); } } // namespace _ipdltest } // namespace mozilla