OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The tests in this file attempt to verify the following through simulation: | 5 // The tests in this file attempt to verify the following through simulation: |
6 // a) That a server experiencing overload will actually benefit from the | 6 // a) That a server experiencing overload will actually benefit from the |
7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside | 7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside |
8 // and be distributed over a longer period of time; | 8 // and be distributed over a longer period of time; |
9 // b) That "well-behaved" clients of a server under DDoS attack actually | 9 // b) That "well-behaved" clients of a server under DDoS attack actually |
10 // benefit from the anti-DDoS throttling logic; and | 10 // benefit from the anti-DDoS throttling logic; and |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 virtual void AdvanceTime(const TimeTicks& absolute_time) = 0; | 70 virtual void AdvanceTime(const TimeTicks& absolute_time) = 0; |
71 virtual void PerformAction() = 0; | 71 virtual void PerformAction() = 0; |
72 }; | 72 }; |
73 | 73 |
74 DiscreteTimeSimulation() {} | 74 DiscreteTimeSimulation() {} |
75 | 75 |
76 // Adds an |actor| to the simulation. The client of the simulation maintains | 76 // Adds an |actor| to the simulation. The client of the simulation maintains |
77 // ownership of |actor| and must ensure its lifetime exceeds that of the | 77 // ownership of |actor| and must ensure its lifetime exceeds that of the |
78 // simulation. Actors should be added in the order you wish for them to | 78 // simulation. Actors should be added in the order you wish for them to |
79 // act at each tick of the simulation. | 79 // act at each tick of the simulation. |
80 void AddActor(Actor* actor) { | 80 void AddActor(Actor* actor) { actors_.push_back(actor); } |
81 actors_.push_back(actor); | |
82 } | |
83 | 81 |
84 // Runs the simulation for, pretending |time_between_ticks| passes from one | 82 // Runs the simulation for, pretending |time_between_ticks| passes from one |
85 // tick to the next. The start time will be the current real time. The | 83 // tick to the next. The start time will be the current real time. The |
86 // simulation will stop when the simulated duration is equal to or greater | 84 // simulation will stop when the simulated duration is equal to or greater |
87 // than |maximum_simulated_duration|. | 85 // than |maximum_simulated_duration|. |
88 void RunSimulation(const TimeDelta& maximum_simulated_duration, | 86 void RunSimulation(const TimeDelta& maximum_simulated_duration, |
89 const TimeDelta& time_between_ticks) { | 87 const TimeDelta& time_between_ticks) { |
90 TimeTicks start_time = TimeTicks(); | 88 TimeTicks start_time = TimeTicks(); |
91 TimeTicks now = start_time; | 89 TimeTicks now = start_time; |
92 while ((now - start_time) <= maximum_simulated_duration) { | 90 while ((now - start_time) <= maximum_simulated_duration) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 } | 149 } |
152 | 150 |
153 requests_per_tick_.push_back(num_current_tick_queries_); | 151 requests_per_tick_.push_back(num_current_tick_queries_); |
154 num_current_tick_queries_ = 0; | 152 num_current_tick_queries_ = 0; |
155 } | 153 } |
156 | 154 |
157 // This is called by Requester. It returns the response code from | 155 // This is called by Requester. It returns the response code from |
158 // the server. | 156 // the server. |
159 int HandleRequest() { | 157 int HandleRequest() { |
160 ++num_current_tick_queries_; | 158 ++num_current_tick_queries_; |
161 if (!start_downtime_.is_null() && | 159 if (!start_downtime_.is_null() && start_downtime_ < now_ && |
162 start_downtime_ < now_ && now_ < end_downtime_) { | 160 now_ < end_downtime_) { |
163 // For the simulation measuring the increase in perceived | 161 // For the simulation measuring the increase in perceived |
164 // downtime, it might be interesting to count separately the | 162 // downtime, it might be interesting to count separately the |
165 // queries seen by the server (assuming a front-end reverse proxy | 163 // queries seen by the server (assuming a front-end reverse proxy |
166 // is what actually serves up the 503s in this case) so that we could | 164 // is what actually serves up the 503s in this case) so that we could |
167 // visualize the traffic spike seen by the server when it comes up, | 165 // visualize the traffic spike seen by the server when it comes up, |
168 // which would in many situations be ameliorated by the anti-DDoS | 166 // which would in many situations be ameliorated by the anti-DDoS |
169 // throttling. | 167 // throttling. |
170 return 503; | 168 return 503; |
171 } | 169 } |
172 | 170 |
173 if ((num_overloaded_ticks_remaining_ > 0 || | 171 if ((num_overloaded_ticks_remaining_ > 0 || |
174 num_current_tick_queries_ > max_queries_per_tick_) && | 172 num_current_tick_queries_ > max_queries_per_tick_) && |
175 base::RandDouble() < request_drop_ratio_) { | 173 base::RandDouble() < request_drop_ratio_) { |
176 return 503; | 174 return 503; |
177 } | 175 } |
178 | 176 |
179 return 200; | 177 return 200; |
180 } | 178 } |
181 | 179 |
182 int num_overloaded_ticks() const { | 180 int num_overloaded_ticks() const { return num_overloaded_ticks_; } |
183 return num_overloaded_ticks_; | |
184 } | |
185 | 181 |
186 int max_experienced_queries_per_tick() const { | 182 int max_experienced_queries_per_tick() const { |
187 return max_experienced_queries_per_tick_; | 183 return max_experienced_queries_per_tick_; |
188 } | 184 } |
189 | 185 |
190 const URLRequest& mock_request() const { | 186 const URLRequest& mock_request() const { return mock_request_; } |
191 return mock_request_; | |
192 } | |
193 | 187 |
194 std::string VisualizeASCII(int terminal_width) { | 188 std::string VisualizeASCII(int terminal_width) { |
195 // Account for | characters we place at left of graph. | 189 // Account for | characters we place at left of graph. |
196 terminal_width -= 1; | 190 terminal_width -= 1; |
197 | 191 |
198 VerboseOut("Overloaded for %d of %d ticks.\n", | 192 VerboseOut("Overloaded for %d of %d ticks.\n", |
199 num_overloaded_ticks_, requests_per_tick_.size()); | 193 num_overloaded_ticks_, |
| 194 requests_per_tick_.size()); |
200 VerboseOut("Got maximum of %d requests in a tick.\n\n", | 195 VerboseOut("Got maximum of %d requests in a tick.\n\n", |
201 max_experienced_queries_per_tick_); | 196 max_experienced_queries_per_tick_); |
202 | 197 |
203 VerboseOut("Traffic graph:\n\n"); | 198 VerboseOut("Traffic graph:\n\n"); |
204 | 199 |
205 // Printing the graph like this is a bit overkill, but was very useful | 200 // Printing the graph like this is a bit overkill, but was very useful |
206 // while developing the various simulations to see if they were testing | 201 // while developing the various simulations to see if they were testing |
207 // the corner cases we want to simulate. | 202 // the corner cases we want to simulate. |
208 | 203 |
209 // Find the smallest number of whole ticks we need to group into a | 204 // Find the smallest number of whole ticks we need to group into a |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 mock_backoff_entry_(&backoff_policy_) {} | 296 mock_backoff_entry_(&backoff_policy_) {} |
302 | 297 |
303 virtual const BackoffEntry* GetBackoffEntry() const OVERRIDE { | 298 virtual const BackoffEntry* GetBackoffEntry() const OVERRIDE { |
304 return &mock_backoff_entry_; | 299 return &mock_backoff_entry_; |
305 } | 300 } |
306 | 301 |
307 virtual BackoffEntry* GetBackoffEntry() OVERRIDE { | 302 virtual BackoffEntry* GetBackoffEntry() OVERRIDE { |
308 return &mock_backoff_entry_; | 303 return &mock_backoff_entry_; |
309 } | 304 } |
310 | 305 |
311 virtual TimeTicks ImplGetTimeNow() const OVERRIDE { | 306 virtual TimeTicks ImplGetTimeNow() const OVERRIDE { return fake_now_; } |
312 return fake_now_; | |
313 } | |
314 | 307 |
315 void SetFakeNow(const TimeTicks& fake_time) { | 308 void SetFakeNow(const TimeTicks& fake_time) { |
316 fake_now_ = fake_time; | 309 fake_now_ = fake_time; |
317 mock_backoff_entry_.set_fake_now(fake_time); | 310 mock_backoff_entry_.set_fake_now(fake_time); |
318 } | 311 } |
319 | 312 |
320 TimeTicks fake_now() const { | 313 TimeTicks fake_now() const { return fake_now_; } |
321 return fake_now_; | |
322 } | |
323 | 314 |
324 protected: | 315 protected: |
325 virtual ~MockURLRequestThrottlerEntry() {} | 316 virtual ~MockURLRequestThrottlerEntry() {} |
326 | 317 |
327 private: | 318 private: |
328 TimeTicks fake_now_; | 319 TimeTicks fake_now_; |
329 MockBackoffEntry mock_backoff_entry_; | 320 MockBackoffEntry mock_backoff_entry_; |
330 }; | 321 }; |
331 | 322 |
332 // Registry of results for a class of |Requester| objects (e.g. attackers vs. | 323 // Registry of results for a class of |Requester| objects (e.g. attackers vs. |
333 // regular clients). | 324 // regular clients). |
334 class RequesterResults { | 325 class RequesterResults { |
335 public: | 326 public: |
336 RequesterResults() | 327 RequesterResults() |
337 : num_attempts_(0), num_successful_(0), num_failed_(0), num_blocked_(0) { | 328 : num_attempts_(0), num_successful_(0), num_failed_(0), num_blocked_(0) {} |
338 } | |
339 | 329 |
340 void AddSuccess() { | 330 void AddSuccess() { |
341 ++num_attempts_; | 331 ++num_attempts_; |
342 ++num_successful_; | 332 ++num_successful_; |
343 } | 333 } |
344 | 334 |
345 void AddFailure() { | 335 void AddFailure() { |
346 ++num_attempts_; | 336 ++num_attempts_; |
347 ++num_failed_; | 337 ++num_failed_; |
348 } | 338 } |
349 | 339 |
350 void AddBlocked() { | 340 void AddBlocked() { |
351 ++num_attempts_; | 341 ++num_attempts_; |
352 ++num_blocked_; | 342 ++num_blocked_; |
353 } | 343 } |
354 | 344 |
355 int num_attempts() const { return num_attempts_; } | 345 int num_attempts() const { return num_attempts_; } |
356 int num_successful() const { return num_successful_; } | 346 int num_successful() const { return num_successful_; } |
357 int num_failed() const { return num_failed_; } | 347 int num_failed() const { return num_failed_; } |
358 int num_blocked() const { return num_blocked_; } | 348 int num_blocked() const { return num_blocked_; } |
359 | 349 |
360 double GetBlockedRatio() { | 350 double GetBlockedRatio() { |
361 DCHECK(num_attempts_); | 351 DCHECK(num_attempts_); |
362 return static_cast<double>(num_blocked_) / | 352 return static_cast<double>(num_blocked_) / |
363 static_cast<double>(num_attempts_); | 353 static_cast<double>(num_attempts_); |
364 } | 354 } |
365 | 355 |
366 double GetSuccessRatio() { | 356 double GetSuccessRatio() { |
367 DCHECK(num_attempts_); | 357 DCHECK(num_attempts_); |
368 return static_cast<double>(num_successful_) / | 358 return static_cast<double>(num_successful_) / |
369 static_cast<double>(num_attempts_); | 359 static_cast<double>(num_attempts_); |
370 } | 360 } |
371 | 361 |
372 void PrintResults(const char* class_description) { | 362 void PrintResults(const char* class_description) { |
373 if (num_attempts_ == 0) { | 363 if (num_attempts_ == 0) { |
374 VerboseOut("No data for %s\n", class_description); | 364 VerboseOut("No data for %s\n", class_description); |
375 return; | 365 return; |
376 } | 366 } |
377 | 367 |
378 VerboseOut("Requester results for %s\n", class_description); | 368 VerboseOut("Requester results for %s\n", class_description); |
379 VerboseOut(" %d attempts\n", num_attempts_); | 369 VerboseOut(" %d attempts\n", num_attempts_); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 | 446 |
457 time_of_last_attempt_ = throttler_entry_->fake_now(); | 447 time_of_last_attempt_ = throttler_entry_->fake_now(); |
458 } | 448 } |
459 } | 449 } |
460 | 450 |
461 // Adds a delay until the first request, equal to a uniformly distributed | 451 // Adds a delay until the first request, equal to a uniformly distributed |
462 // value between now and now + max_delay. | 452 // value between now and now + max_delay. |
463 void SetStartupJitter(const TimeDelta& max_delay) { | 453 void SetStartupJitter(const TimeDelta& max_delay) { |
464 int delay_ms = base::RandInt(0, max_delay.InMilliseconds()); | 454 int delay_ms = base::RandInt(0, max_delay.InMilliseconds()); |
465 time_of_last_attempt_ = TimeTicks() + | 455 time_of_last_attempt_ = TimeTicks() + |
466 TimeDelta::FromMilliseconds(delay_ms) - time_between_requests_; | 456 TimeDelta::FromMilliseconds(delay_ms) - |
| 457 time_between_requests_; |
467 } | 458 } |
468 | 459 |
469 void SetRequestJitter(const TimeDelta& request_jitter) { | 460 void SetRequestJitter(const TimeDelta& request_jitter) { |
470 request_jitter_ = request_jitter; | 461 request_jitter_ = request_jitter; |
471 } | 462 } |
472 | 463 |
473 TimeDelta last_downtime_duration() const { return last_downtime_duration_; } | 464 TimeDelta last_downtime_duration() const { return last_downtime_duration_; } |
474 | 465 |
475 private: | 466 private: |
476 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry_; | 467 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry_; |
(...skipping 19 matching lines...) Expand all Loading... |
496 URLRequestThrottlerManager manager; | 487 URLRequestThrottlerManager manager; |
497 ScopedVector<Requester> requesters; | 488 ScopedVector<Requester> requesters; |
498 for (size_t i = 0; i < kNumAttackers; ++i) { | 489 for (size_t i = 0; i < kNumAttackers; ++i) { |
499 // Use a tiny time_between_requests so the attackers will ping the | 490 // Use a tiny time_between_requests so the attackers will ping the |
500 // server at every tick of the simulation. | 491 // server at every tick of the simulation. |
501 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( | 492 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( |
502 new MockURLRequestThrottlerEntry(&manager)); | 493 new MockURLRequestThrottlerEntry(&manager)); |
503 if (!enable_throttling) | 494 if (!enable_throttling) |
504 throttler_entry->DisableBackoffThrottling(); | 495 throttler_entry->DisableBackoffThrottling(); |
505 | 496 |
506 Requester* attacker = new Requester(throttler_entry.get(), | 497 Requester* attacker = new Requester(throttler_entry.get(), |
507 TimeDelta::FromMilliseconds(1), | 498 TimeDelta::FromMilliseconds(1), |
508 server, | 499 server, |
509 attacker_results); | 500 attacker_results); |
510 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); | 501 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); |
511 requesters.push_back(attacker); | 502 requesters.push_back(attacker); |
512 simulation.AddActor(attacker); | 503 simulation.AddActor(attacker); |
513 } | 504 } |
514 for (size_t i = 0; i < kNumClients; ++i) { | 505 for (size_t i = 0; i < kNumClients; ++i) { |
515 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. | 506 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. |
516 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( | 507 scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 requester.SetStartupJitter(duration / 3); | 598 requester.SetStartupJitter(duration / 3); |
608 requester.SetRequestJitter(average_client_interval); | 599 requester.SetRequestJitter(average_client_interval); |
609 | 600 |
610 DiscreteTimeSimulation simulation; | 601 DiscreteTimeSimulation simulation; |
611 simulation.AddActor(&requester); | 602 simulation.AddActor(&requester); |
612 simulation.AddActor(&server); | 603 simulation.AddActor(&server); |
613 | 604 |
614 simulation.RunSimulation(duration * 2, time_between_ticks); | 605 simulation.RunSimulation(duration * 2, time_between_ticks); |
615 | 606 |
616 return static_cast<double>( | 607 return static_cast<double>( |
617 requester.last_downtime_duration().InMilliseconds()) / | 608 requester.last_downtime_duration().InMilliseconds()) / |
618 static_cast<double>(duration.InMilliseconds()); | 609 static_cast<double>(duration.InMilliseconds()); |
619 } | 610 } |
620 | 611 |
621 TEST(URLRequestThrottlerSimulation, PerceivedDowntimeRatio) { | 612 TEST(URLRequestThrottlerSimulation, PerceivedDowntimeRatio) { |
622 struct Stats { | 613 struct Stats { |
623 // Expected interval that we expect the ratio of downtime when anti-DDoS | 614 // Expected interval that we expect the ratio of downtime when anti-DDoS |
624 // is enabled and downtime when anti-DDoS is not enabled to fall within. | 615 // is enabled and downtime when anti-DDoS is not enabled to fall within. |
625 // | 616 // |
626 // The expected interval depends on two things: The exponential back-off | 617 // The expected interval depends on two things: The exponential back-off |
627 // policy encoded in URLRequestThrottlerEntry, and the test or set of | 618 // policy encoded in URLRequestThrottlerEntry, and the test or set of |
628 // tests that the Stats object is tracking (e.g. a test where the client | 619 // tests that the Stats object is tracking (e.g. a test where the client |
(...skipping 13 matching lines...) Expand all Loading... |
642 double total_ratio_unprotected; | 633 double total_ratio_unprotected; |
643 double total_ratio_protected; | 634 double total_ratio_protected; |
644 | 635 |
645 bool DidConverge(double* increase_ratio_out) { | 636 bool DidConverge(double* increase_ratio_out) { |
646 double unprotected_ratio = total_ratio_unprotected / num_runs; | 637 double unprotected_ratio = total_ratio_unprotected / num_runs; |
647 double protected_ratio = total_ratio_protected / num_runs; | 638 double protected_ratio = total_ratio_protected / num_runs; |
648 double increase_ratio = protected_ratio / unprotected_ratio; | 639 double increase_ratio = protected_ratio / unprotected_ratio; |
649 if (increase_ratio_out) | 640 if (increase_ratio_out) |
650 *increase_ratio_out = increase_ratio; | 641 *increase_ratio_out = increase_ratio; |
651 return expected_min_increase <= increase_ratio && | 642 return expected_min_increase <= increase_ratio && |
652 increase_ratio <= expected_max_increase; | 643 increase_ratio <= expected_max_increase; |
653 } | 644 } |
654 | 645 |
655 void ReportTrialResult(double increase_ratio) { | 646 void ReportTrialResult(double increase_ratio) { |
656 VerboseOut( | 647 VerboseOut( |
657 " Perceived downtime with throttling is %.4f times without.\n", | 648 " Perceived downtime with throttling is %.4f times without.\n", |
658 increase_ratio); | 649 increase_ratio); |
659 VerboseOut(" Test result after %d trials.\n", num_runs); | 650 VerboseOut(" Test result after %d trials.\n", num_runs); |
660 } | 651 } |
661 }; | 652 }; |
662 | 653 |
663 Stats global_stats = { 1.08, 1.15 }; | 654 Stats global_stats = {1.08, 1.15}; |
664 | 655 |
665 struct Trial { | 656 struct Trial { |
666 TimeDelta duration; | 657 TimeDelta duration; |
667 TimeDelta average_client_interval; | 658 TimeDelta average_client_interval; |
668 Stats stats; | 659 Stats stats; |
669 | 660 |
670 void PrintTrialDescription() { | 661 void PrintTrialDescription() { |
671 double duration_minutes = | 662 double duration_minutes = |
672 static_cast<double>(duration.InSeconds()) / 60.0; | 663 static_cast<double>(duration.InSeconds()) / 60.0; |
673 double interval_minutes = | 664 double interval_minutes = |
674 static_cast<double>(average_client_interval.InSeconds()) / 60.0; | 665 static_cast<double>(average_client_interval.InSeconds()) / 60.0; |
675 VerboseOut("Trial with %.2f min downtime, avg. interval %.2f min.\n", | 666 VerboseOut("Trial with %.2f min downtime, avg. interval %.2f min.\n", |
676 duration_minutes, interval_minutes); | 667 duration_minutes, |
| 668 interval_minutes); |
677 } | 669 } |
678 }; | 670 }; |
679 | 671 |
680 // We don't set or check expected ratio intervals on individual | 672 // We don't set or check expected ratio intervals on individual |
681 // experiments as this might make the test too fragile, but we | 673 // experiments as this might make the test too fragile, but we |
682 // print them out at the end for manual evaluation (we want to be | 674 // print them out at the end for manual evaluation (we want to be |
683 // able to make claims about the expected ratios depending on the | 675 // able to make claims about the expected ratios depending on the |
684 // type of behavior of the client and the downtime, e.g. the difference | 676 // type of behavior of the client and the downtime, e.g. the difference |
685 // in behavior between a client making requests every few minutes vs. | 677 // in behavior between a client making requests every few minutes vs. |
686 // one that makes a request every 15 seconds). | 678 // one that makes a request every 15 seconds). |
687 Trial trials[] = { | 679 Trial trials[] = { |
688 { TimeDelta::FromSeconds(10), TimeDelta::FromSeconds(3) }, | 680 {TimeDelta::FromSeconds(10), TimeDelta::FromSeconds(3)}, |
689 { TimeDelta::FromSeconds(30), TimeDelta::FromSeconds(7) }, | 681 {TimeDelta::FromSeconds(30), TimeDelta::FromSeconds(7)}, |
690 { TimeDelta::FromMinutes(5), TimeDelta::FromSeconds(30) }, | 682 {TimeDelta::FromMinutes(5), TimeDelta::FromSeconds(30)}, |
691 { TimeDelta::FromMinutes(10), TimeDelta::FromSeconds(20) }, | 683 {TimeDelta::FromMinutes(10), TimeDelta::FromSeconds(20)}, |
692 { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(15) }, | 684 {TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(15)}, |
693 { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(50) }, | 685 {TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(50)}, |
694 { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(2) }, | 686 {TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(2)}, |
695 { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(5) }, | 687 {TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(5)}, |
696 { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(7) }, | 688 {TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(7)}, |
697 { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(2) }, | 689 {TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(2)}, |
698 { TimeDelta::FromMinutes(40), TimeDelta::FromSeconds(15) }, | 690 {TimeDelta::FromMinutes(40), TimeDelta::FromSeconds(15)}, |
699 { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(7) }, | 691 {TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(7)}, |
700 { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(2) }, | 692 {TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(2)}, |
701 { TimeDelta::FromMinutes(60), TimeDelta::FromSeconds(15) }, | 693 {TimeDelta::FromMinutes(60), TimeDelta::FromSeconds(15)}, |
702 { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(20) }, | 694 {TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(20)}, |
703 { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(3) }, | 695 {TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(3)}, |
704 { TimeDelta::FromMinutes(80), TimeDelta::FromSeconds(15) }, | 696 {TimeDelta::FromMinutes(80), TimeDelta::FromSeconds(15)}, |
705 | 697 |
706 // Most brutal? | 698 // Most brutal? |
707 { TimeDelta::FromMinutes(45), TimeDelta::FromMilliseconds(500) }, | 699 {TimeDelta::FromMinutes(45), TimeDelta::FromMilliseconds(500)}, |
708 }; | 700 }; |
709 | 701 |
710 // If things don't converge by the time we've done 100K trials, then | 702 // If things don't converge by the time we've done 100K trials, then |
711 // clearly one or more of the expected intervals are wrong. | 703 // clearly one or more of the expected intervals are wrong. |
712 while (global_stats.num_runs < 100000) { | 704 while (global_stats.num_runs < 100000) { |
713 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(trials); ++i) { | 705 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(trials); ++i) { |
714 ++global_stats.num_runs; | 706 ++global_stats.num_runs; |
715 ++trials[i].stats.num_runs; | 707 ++trials[i].stats.num_runs; |
716 double ratio_unprotected = SimulateDowntime( | 708 double ratio_unprotected = SimulateDowntime( |
717 trials[i].duration, trials[i].average_client_interval, false); | 709 trials[i].duration, trials[i].average_client_interval, false); |
(...skipping 27 matching lines...) Expand all Loading... |
745 trials[i].PrintTrialDescription(); | 737 trials[i].PrintTrialDescription(); |
746 trials[i].stats.ReportTrialResult(increase_ratio); | 738 trials[i].stats.ReportTrialResult(increase_ratio); |
747 } | 739 } |
748 | 740 |
749 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); | 741 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); |
750 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); | 742 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); |
751 } | 743 } |
752 | 744 |
753 } // namespace | 745 } // namespace |
754 } // namespace net | 746 } // namespace net |
OLD | NEW |