http_benchmark.cc 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #include <csignal>
  2. #include <vector>
  3. #include "base/utils/string/str_utils.h"
  4. #include "fmt/chrono.h"
  5. #include "fmt/format.h"
  6. #include "gflags/gflags.h"
  7. #include "net_io/server/http_server/http_server.h"
  8. #include "nlohmann/json.hpp"
  9. using namespace lt::net;
  10. using namespace lt;
  11. using namespace base;
  12. using namespace co;
  13. DEFINE_int32(loops, 4, "how many loops use for handle message and io");
  14. DEFINE_bool(echo, false, "just echo response without any logic");
  15. DEFINE_bool(coro, false, "using coro context handle request");
  16. DEFINE_string(http,
  17. "0.0.0.0:5006",
  18. "host:port used for http service listen on");
  19. class HttpBenchServer {
  20. public:
  21. ~HttpBenchServer() {
  22. LOG(INFO) << __func__ << " close app";
  23. for (auto loop : loops) {
  24. delete loop;
  25. }
  26. loops.clear();
  27. }
  28. void Run() {
  29. json_message["message"] = "Hello, World!";
  30. int loop_count =
  31. std::max(FLAGS_loops, int(std::thread::hardware_concurrency()));
  32. LOG(INFO) << __func__ << " use loop count:" << loop_count;
  33. for (int i = 0; i < loop_count; i++) {
  34. loops.push_back(new base::MessageLoop(fmt::format("io_{}", i)));
  35. loops.back()->Start();
  36. CoroRunner::RegisteRunner(loops.back());
  37. }
  38. auto func = [this](const RefHttpRequestCtx& context) {
  39. const HttpRequest* req = context->Request();
  40. // TODO: response freelist
  41. auto response = HttpResponse::CreateWithCode(200);
  42. response->SetKeepAlive(req->IsKeepAlive());
  43. if (FLAGS_echo) {
  44. response->MutableBody() = "echo";
  45. } else {
  46. response->InsertHeader("Server", "ltio");
  47. auto tm = fmt::gmtime(std::time(nullptr));
  48. response->InsertHeader("Date",
  49. fmt::format("{:%a, %d %b %Y %H:%M:%S %Z}", tm));
  50. if (req->RequestUrl() == "/plaintext") {
  51. response->MutableBody() = "Hello, World!";
  52. } else if (req->RequestUrl() == "/json") {
  53. response->InsertHeader("Content-Type", "application/json");
  54. response->MutableBody() = std::move(json_message.dump());
  55. }
  56. }
  57. return context->Response(response);
  58. };
  59. handler.reset(FLAGS_coro ? NewHttpCoroHandler(func) : NewHttpHandler(func));
  60. // ProfilerStart("perf.out");
  61. http_server.WithIOLoops(loops)
  62. .WithAddress(base::StrUtil::Concat("http://", FLAGS_http))
  63. .ServeAddress(handler.get());
  64. loops.back()->WaitLoopEnd();
  65. }
  66. void Stop() {
  67. CHECK(CO_CANYIELD);
  68. LOG(INFO) << __FUNCTION__ << " stop enter";
  69. http_server.StopServer(CO_RESUMER);
  70. CO_YIELD;
  71. LOG(INFO) << __FUNCTION__ << " stop leave";
  72. loops.back()->QuitLoop();
  73. }
  74. HttpServer http_server;
  75. std::unique_ptr<CodecService::Handler> handler;
  76. base::MessageLoop main_loop;
  77. nlohmann::json json_message;
  78. std::vector<base::MessageLoop*> loops;
  79. };
  80. HttpBenchServer app;
  81. void signalHandler(int signum) {
  82. LOG(INFO) << "sighandler sig:" << signum;
  83. CO_GO std::bind(&HttpBenchServer::Stop, &app);
  84. }
  85. int main(int argc, char* argv[]) {
  86. gflags::ParseCommandLineFlags(&argc, &argv, true);
  87. gflags::SetUsageMessage("usage: exec --http=ip:port ");
  88. // google::InitGoogleLogging(argv[0]);
  89. // google::SetVLOGLevel(NULL, 26);
  90. signal(SIGINT, signalHandler);
  91. signal(SIGTERM, signalHandler);
  92. app.Run();
  93. }