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();
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) round_trip = msg.substr(p);
57
58 } else if (arg == "halt") {
59 // terminate ROOT
60 window_terminated = true;
61 window->TerminateROOT();
62 }
63}
64
65////////////////////////////////////////////////////////
66/// @param nclients - number of clients
67/// @param test_mode
68/// 0 - default config, no special threads
69/// 1 - reduce http server timer
70/// 2 - create special thread in THttpServer and use it
71/// 3 - also create special thread for RWebWindow
72/// 4 - directly use civetweb threads (only for experts)
73/// 10 - force longpoll socket with default config
74
75enum TestModes {
76 modeDefault = 0, // default configuration
77 modeMinimalTimer = 1, // reduce THttpServer timer
78 modeHttpThread = 2, // create and use THttpServer thread to handle window functionality
79 modeHttpWindowThread = 3, // with THttpServer thread also create thread for the window
80 modeCivetThread = 4 // directly use threads if civetweb, dangerous
81};
82
83enum MajorModes {
84 majorDefault = 0, // default test suite, using websockets
85 majorLongpoll = 1 // force longpoll sockets
86};
87
88void ping(int nclients = 1, int test_mode = 0)
89{
91
92 batch_mode = gROOT->IsBatch();
93
94 // verify values
95 if (test_mode < 0) test_mode = 0;
96 int major_mode = test_mode / 10;
97 test_mode = test_mode % 10;
100
101 if (num_clients < 1)
102 num_clients = 1;
103 else if (num_clients > 1000)
104 num_clients = 1000;
105
106 // let force usage of longpoll engine instead of plain websocket
108 gEnv->SetValue("WebGui.WSLongpoll", "yes");
109
110 if (num_clients > 5)
111 gEnv->SetValue("WebGui.HttpThreads", num_clients + 5);
112
113 // allocate special thread for THttpServer, it will be automatically used by web window
115 gEnv->SetValue("WebGui.HttpThrd", "yes");
116
117 // let reduce reaction time of THttpServer
119 gEnv->SetValue("WebGui.HttpTimer", 1);
120
121 // let allocate special thread which will be used to perform data sending via websocket
122 // should reduce consumption of webwindow thread when big data are send
123 // gEnv->SetValue("WebGui.SenderThrds", "yes");
124
125 // create window
126 window = ROOT::RWebWindow::Create();
127
128 // configure number of clients are allowed to connect
130 window->SetConnLimit(num_clients);
131
132 // configure default html page
133 // either HTML code can be specified or just name of file after 'file:' prefix
134 // Detect file location to specify full path to the HTML file
135 std::string fname = __FILE__;
136 auto pos = fname.find("ping.cxx");
137 if (pos > 0)
138 fname.resize(pos);
139 else
140 fname = gROOT->GetTutorialsDir() + std::string("/webgui/ping/");
141 fname.append("ping.html");
142 window->SetDefaultPage("file:" + fname);
143
144 // configure window geometry
145 window->SetGeometry(300, 500);
146
147 // this set call-back, invoked when message received from client
148 // also at this moment thread id is configured which supposed to be used to handle requests
149 window->SetDataCallBack(ProcessData);
150
151 // allow to use server thread, which responsible for requests processing
153 window->UseServerThreads();
154
156 window->StartThread();
157
158 // instead of showing window one can create URL and type it in any browser window
159 if (call_show)
160 window->Show(batch_mode ? "headless" : "");
161 else
162 std::cout << "Window url is: " << window->GetUrl(true) << std::endl;
163
164 // provide blocking method to let run
165 if (batch_mode) {
166 const int run_limit = 200;
167 const double fullrun_time = 100., startup_time = 70.;
168 start_tm = firstmsg_tm = std::chrono::high_resolution_clock::now();
169 window->WaitFor([=](double tm) { return (current_counter >= run_limit) || (tm > fullrun_time) || ((current_counter == 0) && (tm > startup_time)) ? 1 : 0; });
170 stop_tm = std::chrono::high_resolution_clock::now();
171 auto startuptime_int = std::chrono::duration_cast<std::chrono::milliseconds>(firstmsg_tm - start_tm);
172 auto runttime_int = std::chrono::duration_cast<std::chrono::milliseconds>(stop_tm - firstmsg_tm);
173
175 std::cout << "PING-PONG TEST COMPLETED " << round_trip;
176 else
177 std::cout << "PING-PONG TEST FAIL cnt:" << current_counter;
178
179 std::cout << " startup: " << startuptime_int.count() << "ms" << " run: " << runttime_int.count() << "ms" << std::endl;
180 }
181}
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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