Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ping.cxx
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_webgui
3/// This is test suite for RWebWindow communication performance
4/// On the first place latency of round-trip (ping-pong) packet is measured
5/// File ping.cxx implements server-side code of RWebWindow
6/// In ping.html client code plus visualization is provided.
7///
8/// \macro_code
9///
10/// \author Sergey Linev
11
12#include <ROOT/RWebWindow.hxx>
13#include <iostream>
14#include <chrono>
15
16std::shared_ptr<ROOT::Experimental::RWebWindow> window;
17
18int num_clients = 1;
19bool window_terminated = false;
20bool call_show = true;
21bool batch_mode = false;
22int current_counter = 0;
23
24auto start_tm = std::chrono::high_resolution_clock::now();
25auto firstmsg_tm = start_tm;
26auto stop_tm = start_tm;
27std::string round_trip = "<not defined>";
28
29void ProcessData(unsigned connid, const std::string &arg)
30{
31 if (arg.find("PING:") == 0) {
32 window->Send(connid, arg);
33 } else if (arg == "first") {
34 // first message to provide config
35 firstmsg_tm = std::chrono::high_resolution_clock::now();
36 window->Send(connid, std::string("CLIENTS:") + std::to_string(num_clients));
37 } else if (arg.find("SHOW:") == 0) {
38 std::string msg = arg.substr(5);
39 if (!batch_mode)
40 std::cout << msg << std::endl;
41 if (msg.find("Cnt:") == 0) {
42 int counter = std::stoi(msg.substr(4));
43 if (counter > 0)
44 current_counter = counter;
45 }
46
47 auto p = msg.find("round-trip:");
48 if (p > 0) round_trip = msg.substr(p);
49
50 } else if (arg == "halt") {
51 // terminate ROOT
52 window_terminated = true;
53 window->TerminateROOT();
54 }
55}
56
57////////////////////////////////////////////////////////
58/// @param nclients - number of clients
59/// @param test_mode
60/// 0 - default config, no special threads
61/// 1 - reduce http server timer
62/// 2 - create special thread in THttpServer and use it
63/// 3 - also create special thread for RWebWindow
64/// 4 - directly use civetweb threads (only for experts)
65/// 10 - force longpoll socket with default config
66
67enum TestModes {
68 modeDefault = 0, // default configuration
69 modeMinimalTimer = 1, // reduce THttpServer timer
70 modeHttpThread = 2, // create and use THttpServer thread to handle window functionality
71 modeHttpWindowThread = 3, // with THttpServer thread also create thread for the window
72 modeCivetThread = 4 // directly use threads if civetweb, dangerous
73};
74
75enum MajorModes {
76 majorDefault = 0, // default test suite, using websockets
77 majorLongpoll = 1 // force longpoll sockets
78};
79
80void ping(int nclients = 1, int test_mode = 0)
81{
82 num_clients = nclients;
83
84 batch_mode = gROOT->IsBatch();
85
86 // verify values
87 if (test_mode < 0) test_mode = 0;
88 int major_mode = test_mode / 10;
89 test_mode = test_mode % 10;
90 if (test_mode > modeCivetThread)
91 test_mode = modeDefault;
92
93 if (num_clients < 1)
94 num_clients = 1;
95 else if (num_clients > 1000)
96 num_clients = 1000;
97
98 // let force usage of longpoll engine instead of plain websocket
99 if (major_mode == majorLongpoll)
100 gEnv->SetValue("WebGui.WSLongpoll", "yes");
101
102 if (num_clients > 5)
103 gEnv->SetValue("WebGui.HttpThreads", num_clients + 5);
104
105 // allocate special thread for THttpServer, it will be automatically used by web window
106 if ((test_mode == modeHttpThread) || (test_mode == modeHttpWindowThread))
107 gEnv->SetValue("WebGui.HttpThrd", "yes");
108
109 // let reduce reaction time of THttpServer
110 if (test_mode == modeMinimalTimer)
111 gEnv->SetValue("WebGui.HttpTimer", 1);
112
113 // let allocate special thread which will be used to perform data sending via websocket
114 // should reduce consumption of webwindow thread when big data are send
115 // gEnv->SetValue("WebGui.SenderThrds", "yes");
116
117 // create window
119
120 // configure maximal number of clients which allowed to connect
121 window->SetConnLimit(num_clients);
122
123 // configure default html page
124 // either HTML code can be specified or just name of file after 'file:' prefix
125 // Detect file location to specify full path to the
126 std::string fname = __FILE__;
127 auto pos = fname.find("ping.cxx");
128 if (pos > 0) { fname.resize(pos); fname.append("ping.html"); }
129 else fname = "ping.html";
130 window->SetDefaultPage(std::string("file:") + fname);
131
132 // configure window geometry
133 window->SetGeometry(300, 500);
134
135 // this set call-back, invoked when message received from client
136 // also at this moment thread id is configured which supposed to be used to handle requests
137 window->SetDataCallBack(ProcessData);
138
139 // allow to use server thread, which responsible for requests processing
140 if (test_mode == modeCivetThread)
141 window->UseServerThreads();
142
143 if (test_mode == modeHttpWindowThread)
144 window->StartThread();
145
146 // instead of showing window one can create URL and type it in any browser window
147 if (call_show)
148 window->Show(batch_mode ? "headless" : "");
149 else
150 std::cout << "Window url is: " << window->GetUrl(true) << std::endl;
151
152 // provide blocking method to let run
153 if (batch_mode) {
154 const int run_limit = 200;
155 const double fullrun_time = 100., startup_time = 70.;
156 start_tm = firstmsg_tm = std::chrono::high_resolution_clock::now();
157 window->WaitFor([=](double tm) { return (current_counter >= run_limit) || (tm > fullrun_time) || ((current_counter == 0) && (tm > startup_time)) ? 1 : 0; });
158 stop_tm = std::chrono::high_resolution_clock::now();
159 auto startuptime_int = std::chrono::duration_cast<std::chrono::milliseconds>(firstmsg_tm - start_tm);
160 auto runttime_int = std::chrono::duration_cast<std::chrono::milliseconds>(stop_tm - firstmsg_tm);
161
162 if (current_counter >= run_limit)
163 std::cout << "PING-PONG TEST COMPLETED " << round_trip;
164 else
165 std::cout << "PING-PONG TEST FAIL cnt:" << current_counter;
166
167 std::cout << " startup: " << startuptime_int.count() << "ms" << " run: " << runttime_int.count() << "ms" << std::endl;
168 }
169}
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
#define gROOT
Definition TROOT.h:404
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
virtual void SetValue(const char *name, const char *value, EEnvLevel level=kEnvChange, const char *type=nullptr)
Set the value of a resource or create a new resource.
Definition TEnv.cxx:736