1 #include "TestLatency.h"
2 
3 #include "IPDLUnitTests.h"      // fail etc.
4 
5 // A ping/pong trial takes O(100us) or more, so if we don't have 10us
6 // resolution or better, the results will not be terribly useful
7 static const double kTimingResolutionCutoff = 0.00001; // 10us
8 
9 namespace mozilla {
10 namespace _ipdltest {
11 
12 //-----------------------------------------------------------------------------
13 // parent
14 
TestLatencyParent()15 TestLatencyParent::TestLatencyParent() :
16     mStart(),
17     mPPTimeTotal(),
18     mPP5TimeTotal(),
19     mRpcTimeTotal(),
20     mPPTrialsToGo(NR_TRIALS),
21     mPP5TrialsToGo(NR_TRIALS),
22     mNumChildProcessedCompressedSpams(0),
23     mWhichPong5(0)
24 {
25     MOZ_COUNT_CTOR(TestLatencyParent);
26 }
27 
~TestLatencyParent()28 TestLatencyParent::~TestLatencyParent()
29 {
30     MOZ_COUNT_DTOR(TestLatencyParent);
31 }
32 
33 void
Main()34 TestLatencyParent::Main()
35 {
36     TimeDuration resolution = TimeDuration::Resolution();
37     if (resolution.ToSeconds() > kTimingResolutionCutoff) {
38         puts("  (skipping TestLatency, timing resolution is too poor)");
39         Close();
40         return;
41     }
42 
43     printf("  timing resolution: %g seconds\n",
44            resolution.ToSecondsSigDigits());
45 
46     if (mozilla::ipc::LoggingEnabled())
47         MOZ_CRASH("you really don't want to log all IPC messages during this test, trust me");
48 
49     PingPongTrial();
50 }
51 
52 void
PingPongTrial()53 TestLatencyParent::PingPongTrial()
54 {
55     mStart = TimeStamp::Now();
56     if (!SendPing())
57         fail("sending Ping()");
58 }
59 
60 void
Ping5Pong5Trial()61 TestLatencyParent::Ping5Pong5Trial()
62 {
63     mStart = TimeStamp::Now();
64 
65     if (!SendPing5() ||
66         !SendPing5() ||
67         !SendPing5() ||
68         !SendPing5() ||
69         !SendPing5())
70         fail("sending Ping5()");
71 }
72 
73 mozilla::ipc::IPCResult
RecvPong()74 TestLatencyParent::RecvPong()
75 {
76     TimeDuration thisTrial = (TimeStamp::Now() - mStart);
77     mPPTimeTotal += thisTrial;
78 
79     if (0 == (mPPTrialsToGo % 1000))
80         printf("  PP trial %d: %g\n",
81                mPPTrialsToGo, thisTrial.ToSecondsSigDigits());
82 
83     if (--mPPTrialsToGo > 0)
84         PingPongTrial();
85     else
86         Ping5Pong5Trial();
87     return IPC_OK();
88 }
89 
90 mozilla::ipc::IPCResult
RecvPong5()91 TestLatencyParent::RecvPong5()
92 {
93     ++mWhichPong5;
94 
95     // MOZ_ASSERT((PTestLatency::PING5 != state()) == (mWhichPong5 < 5));
96 
97     if (mWhichPong5 < 5) {
98         return IPC_OK();
99     }
100 
101     mWhichPong5 = 0;
102 
103     TimeDuration thisTrial = (TimeStamp::Now() - mStart);
104     mPP5TimeTotal += thisTrial;
105 
106     if (0 == (mPP5TrialsToGo % 1000))
107         printf("  PP5 trial %d: %g\n",
108                mPP5TrialsToGo, thisTrial.ToSecondsSigDigits());
109 
110     if (0 < --mPP5TrialsToGo)
111         Ping5Pong5Trial();
112     else
113         RpcTrials();
114 
115     return IPC_OK();
116 }
117 
118 void
RpcTrials()119 TestLatencyParent::RpcTrials()
120 {
121     TimeStamp start = TimeStamp::Now();
122     for (int i = 0; i < NR_TRIALS; ++i) {
123         if (!CallRpc())
124             fail("can't call Rpc()");
125         if (0 == (i % 1000))
126             printf("  Rpc trial %d\n", i);
127     }
128     mRpcTimeTotal = (TimeStamp::Now() - start);
129 
130     SpamTrial();
131 }
132 
133 void
SpamTrial()134 TestLatencyParent::SpamTrial()
135 {
136     TimeStamp start = TimeStamp::Now();
137     for (int i = 0; i < NR_SPAMS - 1; ++i) {
138         if (!SendSpam())
139             fail("sending Spam()");
140         if (0 == (i % 10000))
141             printf("  Spam trial %d\n", i);
142     }
143 
144     // Synchronize with the child process to ensure all messages have
145     // been processed.  This adds the overhead of a reply message from
146     // child-->here, but should be insignificant compared to >>
147     // NR_SPAMS.
148     if (!CallSynchro())
149         fail("calling Synchro()");
150 
151     mSpamTimeTotal = (TimeStamp::Now() - start);
152 
153     CompressedSpamTrial();
154 }
155 
156 void
CompressedSpamTrial()157 TestLatencyParent::CompressedSpamTrial()
158 {
159     for (int i = 0; i < NR_SPAMS; ++i) {
160         if (!SendCompressedSpam(i + 1))
161             fail("sending CompressedSpam()");
162         if (0 == (i % 10000))
163             printf("  CompressedSpam trial %d\n", i);
164     }
165 
166     uint32_t lastSeqno;
167     if (!CallSynchro2(&lastSeqno, &mNumChildProcessedCompressedSpams))
168         fail("calling Synchro2()");
169 
170     if (lastSeqno != NR_SPAMS)
171         fail("last seqno was %u, expected %u", lastSeqno, NR_SPAMS);
172 
173     // NB: since this is testing an optimization, it's somewhat bogus.
174     // Need to make a warning if it actually intermittently fails in
175     // practice, which is doubtful.
176     if (!(mNumChildProcessedCompressedSpams < NR_SPAMS))
177         fail("Didn't compress any messages?");
178 
179     Exit();
180 }
181 
182 void
Exit()183 TestLatencyParent::Exit()
184 {
185     Close();
186 }
187 
188 //-----------------------------------------------------------------------------
189 // child
190 
TestLatencyChild()191 TestLatencyChild::TestLatencyChild()
192     : mLastSeqno(0)
193     , mNumProcessedCompressedSpams(0)
194     , mWhichPing5(0)
195 {
196     MOZ_COUNT_CTOR(TestLatencyChild);
197 }
198 
~TestLatencyChild()199 TestLatencyChild::~TestLatencyChild()
200 {
201     MOZ_COUNT_DTOR(TestLatencyChild);
202 }
203 
204 mozilla::ipc::IPCResult
RecvPing()205 TestLatencyChild::RecvPing()
206 {
207     SendPong();
208     return IPC_OK();
209 }
210 
211 mozilla::ipc::IPCResult
RecvPing5()212 TestLatencyChild::RecvPing5()
213 {
214     ++mWhichPing5;
215 
216     // MOZ_ASSERT((PTestLatency::PONG1 != state()) == (mWhichPing5 < 5));
217 
218     if (mWhichPing5 < 5) {
219         return IPC_OK();
220     }
221 
222     mWhichPing5 = 0;
223 
224     if (!SendPong5() ||
225         !SendPong5() ||
226         !SendPong5() ||
227         !SendPong5() ||
228         !SendPong5())
229         fail("sending Pong5()");
230 
231     return IPC_OK();
232 }
233 
234 mozilla::ipc::IPCResult
AnswerRpc()235 TestLatencyChild::AnswerRpc()
236 {
237     return IPC_OK();
238 }
239 
240 mozilla::ipc::IPCResult
RecvSpam()241 TestLatencyChild::RecvSpam()
242 {
243     // no-op
244     return IPC_OK();
245 }
246 
247 mozilla::ipc::IPCResult
AnswerSynchro()248 TestLatencyChild::AnswerSynchro()
249 {
250     return IPC_OK();
251 }
252 
253 mozilla::ipc::IPCResult
RecvCompressedSpam(const uint32_t & seqno)254 TestLatencyChild::RecvCompressedSpam(const uint32_t& seqno)
255 {
256     if (seqno <= mLastSeqno)
257         fail("compressed seqnos must monotonically increase");
258 
259     mLastSeqno = seqno;
260     ++mNumProcessedCompressedSpams;
261     return IPC_OK();
262 }
263 
264 mozilla::ipc::IPCResult
AnswerSynchro2(uint32_t * lastSeqno,uint32_t * numMessagesDispatched)265 TestLatencyChild::AnswerSynchro2(uint32_t* lastSeqno,
266                                  uint32_t* numMessagesDispatched)
267 {
268     *lastSeqno = mLastSeqno;
269     *numMessagesDispatched = mNumProcessedCompressedSpams;
270     return IPC_OK();
271 }
272 
273 } // namespace _ipdltest
274 } // namespace mozilla
275