url_request_quic_perftest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <inttypes.h>
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/files/file_path.h"
  9. #include "base/memory/ref_counted_memory.h"
  10. #include "base/run_loop.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/task/single_thread_task_runner.h"
  13. #include "base/test/task_environment.h"
  14. #include "base/time/time.h"
  15. #include "base/trace_event/memory_dump_manager.h"
  16. #include "base/trace_event/memory_dump_manager_test_utils.h"
  17. #include "base/trace_event/memory_dump_request_args.h"
  18. #include "base/trace_event/process_memory_dump.h"
  19. #include "base/trace_event/trace_config.h"
  20. #include "base/trace_event/traced_value.h"
  21. #include "net/base/load_timing_info.h"
  22. #include "net/cert/mock_cert_verifier.h"
  23. #include "net/dns/mapped_host_resolver.h"
  24. #include "net/dns/mock_host_resolver.h"
  25. #include "net/http/http_network_session.h"
  26. #include "net/http/http_status_code.h"
  27. #include "net/quic/crypto/proof_source_chromium.h"
  28. #include "net/quic/quic_context.h"
  29. #include "net/test/cert_test_util.h"
  30. #include "net/test/embedded_test_server/embedded_test_server.h"
  31. #include "net/test/embedded_test_server/http_response.h"
  32. #include "net/test/gtest_util.h"
  33. #include "net/test/test_data_directory.h"
  34. #include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
  35. #include "net/third_party/quiche/src/quiche/quic/tools/quic_memory_cache_backend.h"
  36. #include "net/tools/quic/quic_simple_server.h"
  37. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  38. #include "net/url_request/url_request.h"
  39. #include "net/url_request/url_request_context.h"
  40. #include "net/url_request/url_request_context_builder.h"
  41. #include "net/url_request/url_request_test_util.h"
  42. #include "testing/gmock/include/gmock/gmock.h"
  43. #include "testing/gtest/include/gtest/gtest.h"
  44. #include "testing/perf/perf_result_reporter.h"
  45. #include "url/gurl.h"
  46. using testing::_;
  47. using testing::Invoke;
  48. using testing::Contains;
  49. using testing::Eq;
  50. using testing::ByRef;
  51. using base::trace_event::MemoryAllocatorDump;
  52. namespace net {
  53. namespace {
  54. const int kAltSvcPort = 6121;
  55. const char kOriginHost[] = "mail.example.com";
  56. const char kAltSvcHost[] = "test.example.com";
  57. // Used as a simple response from the server.
  58. const char kHelloPath[] = "/hello.txt";
  59. const char kHelloAltSvcResponse[] = "Hello from QUIC Server";
  60. const char kHelloOriginResponse[] = "Hello from TCP Server";
  61. const int kHelloStatus = 200;
  62. static constexpr char kMetricPrefixURLRequestQuick[] = "URLRequestQuic.";
  63. static constexpr char kMetricRequestTimeMs[] = "request_time";
  64. static constexpr char kMetricActiveQuicJobsCount[] = "active_quic_jobs";
  65. static constexpr char kMetricActiveQuicSessionsCount[] = "active_quic_sessions";
  66. perf_test::PerfResultReporter SetUpURLRequestQuicReporter(
  67. const std::string& story) {
  68. perf_test::PerfResultReporter reporter(kMetricPrefixURLRequestQuick, story);
  69. reporter.RegisterImportantMetric(kMetricRequestTimeMs, "ms");
  70. reporter.RegisterImportantMetric(kMetricActiveQuicJobsCount, "count");
  71. reporter.RegisterImportantMetric(kMetricActiveQuicSessionsCount, "count");
  72. return reporter;
  73. }
  74. std::unique_ptr<test_server::HttpResponse> HandleRequest(
  75. const test_server::HttpRequest& request) {
  76. auto http_response = std::make_unique<test_server::BasicHttpResponse>();
  77. std::string alpn =
  78. quic::AlpnForVersion(DefaultSupportedQuicVersions().front());
  79. http_response->AddCustomHeader(
  80. "Alt-Svc", base::StringPrintf("%s=\"%s:%d\"", alpn.c_str(), kAltSvcHost,
  81. kAltSvcPort));
  82. http_response->set_code(HTTP_OK);
  83. http_response->set_content(kHelloOriginResponse);
  84. http_response->set_content_type("text/plain");
  85. return std::move(http_response);
  86. }
  87. class URLRequestQuicPerfTest : public ::testing::Test {
  88. protected:
  89. URLRequestQuicPerfTest()
  90. : task_environment_(
  91. std::make_unique<base::test::SingleThreadTaskEnvironment>(
  92. base::test::SingleThreadTaskEnvironment::MainThreadType::IO)) {
  93. memory_dump_manager_ =
  94. base::trace_event::MemoryDumpManager::CreateInstanceForTesting();
  95. base::trace_event::InitializeMemoryDumpManagerForInProcessTesting(
  96. /*is_coordinator=*/false);
  97. memory_dump_manager_->set_dumper_registrations_ignored_for_testing(false);
  98. memory_dump_manager_->set_dumper_registrations_ignored_for_testing(true);
  99. StartTcpServer();
  100. StartQuicServer();
  101. // Host mapping.
  102. auto resolver = std::make_unique<MockHostResolver>();
  103. resolver->rules()->AddRule(kAltSvcHost, "127.0.0.1");
  104. auto host_resolver =
  105. std::make_unique<MappedHostResolver>(std::move(resolver));
  106. std::string map_rule = base::StringPrintf("MAP %s 127.0.0.1:%d",
  107. kOriginHost, tcp_server_->port());
  108. EXPECT_TRUE(host_resolver->AddRuleFromString(map_rule));
  109. HttpNetworkSessionParams params;
  110. params.enable_quic = true;
  111. params.enable_user_alternate_protocol_ports = true;
  112. auto quic_context = std::make_unique<QuicContext>();
  113. quic_context->params()->allow_remote_alt_svc = true;
  114. auto context_builder = CreateTestURLRequestContextBuilder();
  115. context_builder->set_host_resolver(std::move(host_resolver));
  116. context_builder->set_http_network_session_params(params);
  117. context_builder->SetCertVerifier(std::make_unique<MockCertVerifier>());
  118. context_builder->set_quic_context(std::move(quic_context));
  119. context_ = context_builder->Build();
  120. }
  121. void TearDown() override {
  122. if (quic_server_) {
  123. quic_server_->Shutdown();
  124. // If possible, deliver the connection close packet to the client before
  125. // destruct the URLRequestContext.
  126. base::RunLoop().RunUntilIdle();
  127. }
  128. // |tcp_server_| shuts down in EmbeddedTestServer destructor.
  129. memory_dump_manager_.reset();
  130. task_environment_.reset();
  131. }
  132. std::unique_ptr<URLRequest> CreateRequest(const GURL& url,
  133. RequestPriority priority,
  134. URLRequest::Delegate* delegate) {
  135. return context_->CreateRequest(url, priority, delegate,
  136. TRAFFIC_ANNOTATION_FOR_TESTS);
  137. }
  138. URLRequestContext* context() const { return context_.get(); }
  139. private:
  140. void StartQuicServer() {
  141. quic::QuicConfig config;
  142. memory_cache_backend_.AddSimpleResponse(kOriginHost, kHelloPath,
  143. kHelloStatus, kHelloAltSvcResponse);
  144. quic_server_ = std::make_unique<QuicSimpleServer>(
  145. quic::test::crypto_test_utils::ProofSourceForTesting(), config,
  146. quic::QuicCryptoServerConfig::ConfigOptions(),
  147. quic::AllSupportedVersions(), &memory_cache_backend_);
  148. int rv = quic_server_->Listen(
  149. net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kAltSvcPort));
  150. ASSERT_GE(rv, 0) << "Quic server fails to start";
  151. CertVerifyResult verify_result;
  152. verify_result.verified_cert = ImportCertFromFile(
  153. GetTestCertsDirectory(), "quic-chain.pem");
  154. verify_result.is_issued_by_known_root = true;
  155. cert_verifier().AddResultForCert(verify_result.verified_cert.get(),
  156. verify_result, OK);
  157. }
  158. void StartTcpServer() {
  159. tcp_server_ = std::make_unique<EmbeddedTestServer>(
  160. net::EmbeddedTestServer::TYPE_HTTPS);
  161. tcp_server_->RegisterRequestHandler(base::BindRepeating(&HandleRequest));
  162. ASSERT_TRUE(tcp_server_->Start()) << "HTTP/1.1 server fails to start";
  163. CertVerifyResult verify_result;
  164. verify_result.verified_cert = tcp_server_->GetCertificate();
  165. cert_verifier().AddResultForCert(tcp_server_->GetCertificate(),
  166. verify_result, OK);
  167. }
  168. MockCertVerifier& cert_verifier() {
  169. // This cast is safe because we set a MockCertVerifier in the constructor.
  170. return *static_cast<MockCertVerifier*>(context_->cert_verifier());
  171. }
  172. std::unique_ptr<base::trace_event::MemoryDumpManager> memory_dump_manager_;
  173. std::unique_ptr<EmbeddedTestServer> tcp_server_;
  174. std::unique_ptr<QuicSimpleServer> quic_server_;
  175. std::unique_ptr<base::test::SingleThreadTaskEnvironment> task_environment_;
  176. std::unique_ptr<URLRequestContext> context_;
  177. quic::QuicMemoryCacheBackend memory_cache_backend_;
  178. };
  179. void CheckScalarInDump(const MemoryAllocatorDump* dump,
  180. const std::string& name,
  181. const char* expected_units,
  182. uint64_t expected_value) {
  183. MemoryAllocatorDump::Entry expected(name, expected_units, expected_value);
  184. EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected))));
  185. }
  186. } // namespace
  187. #if BUILDFLAG(IS_FUCHSIA)
  188. // TODO(crbug.com/852937): Fix this test on Fuchsia and re-enable.
  189. #define MAYBE_TestGetRequest DISABLED_TestGetRequest
  190. #else
  191. #define MAYBE_TestGetRequest TestGetRequest
  192. #endif
  193. TEST_F(URLRequestQuicPerfTest, MAYBE_TestGetRequest) {
  194. bool quic_succeeded = false;
  195. GURL url(base::StringPrintf("https://%s%s", kOriginHost, kHelloPath));
  196. base::TimeTicks start = base::TimeTicks::Now();
  197. const int kNumRequest = 1000;
  198. for (int i = 0; i < kNumRequest; ++i) {
  199. TestDelegate delegate;
  200. std::unique_ptr<URLRequest> request =
  201. CreateRequest(url, DEFAULT_PRIORITY, &delegate);
  202. request->Start();
  203. EXPECT_TRUE(request->is_pending());
  204. base::RunLoop().Run();
  205. EXPECT_EQ(OK, delegate.request_status());
  206. if (delegate.data_received() == kHelloAltSvcResponse) {
  207. quic_succeeded = true;
  208. } else {
  209. EXPECT_EQ(kHelloOriginResponse, delegate.data_received());
  210. }
  211. }
  212. base::TimeTicks end = base::TimeTicks::Now();
  213. auto reporter = SetUpURLRequestQuicReporter("get");
  214. reporter.AddResult(kMetricRequestTimeMs,
  215. (end - start).InMillisecondsF() / kNumRequest);
  216. EXPECT_TRUE(quic_succeeded);
  217. base::trace_event::MemoryDumpManager::GetInstance()->SetupForTracing(
  218. base::trace_event::TraceConfig::MemoryDumpConfig());
  219. base::RunLoop run_loop;
  220. base::trace_event::MemoryDumpRequestArgs args{
  221. 1 /* dump_guid*/, base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
  222. base::trace_event::MemoryDumpLevelOfDetail::LIGHT};
  223. auto on_memory_dump_done =
  224. [](base::OnceClosure quit_closure, const URLRequestContext* context,
  225. bool success, uint64_t dump_guid,
  226. std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd) {
  227. ASSERT_TRUE(success);
  228. const auto& allocator_dumps = pmd->allocator_dumps();
  229. auto it = allocator_dumps.find(
  230. base::StringPrintf("net/url_request_context/unknown/0x%" PRIxPTR,
  231. reinterpret_cast<uintptr_t>(context)));
  232. ASSERT_NE(allocator_dumps.end(), it);
  233. MemoryAllocatorDump* url_request_context_dump = it->second.get();
  234. CheckScalarInDump(
  235. url_request_context_dump,
  236. base::trace_event::MemoryAllocatorDump::kNameObjectCount,
  237. base::trace_event::MemoryAllocatorDump::kUnitsObjects, 0);
  238. it = allocator_dumps.find(base::StringPrintf(
  239. "net/http_network_session_0x%" PRIxPTR "/quic_stream_factory",
  240. reinterpret_cast<uintptr_t>(
  241. context->http_transaction_factory()->GetSession())));
  242. ASSERT_NE(allocator_dumps.end(), it);
  243. MemoryAllocatorDump* quic_stream_factory_dump = it->second.get();
  244. CheckScalarInDump(quic_stream_factory_dump, "active_jobs",
  245. base::trace_event::MemoryAllocatorDump::kUnitsObjects,
  246. 0);
  247. CheckScalarInDump(quic_stream_factory_dump, "all_sessions",
  248. base::trace_event::MemoryAllocatorDump::kUnitsObjects,
  249. 1);
  250. std::string stream_factory_dump_name = base::StringPrintf(
  251. "net/http_network_session_0x%" PRIxPTR "/stream_factory",
  252. reinterpret_cast<uintptr_t>(
  253. context->http_transaction_factory()->GetSession()));
  254. ASSERT_EQ(0u, allocator_dumps.count(stream_factory_dump_name));
  255. std::move(quit_closure).Run();
  256. };
  257. base::trace_event::MemoryDumpManager::GetInstance()->CreateProcessDump(
  258. args,
  259. base::BindOnce(on_memory_dump_done, run_loop.QuitClosure(), context()));
  260. run_loop.Run();
  261. base::trace_event::MemoryDumpManager::GetInstance()->TeardownForTracing();
  262. }
  263. } // namespace net