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