836f2ba70f08dd276dd698581ecb85d17476fdbe
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / network-performance-client.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/network/common/network-performance-client.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdio.h>
23 #include <string>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/network/common/automation.h>
27 #include <dali/internal/network/common/network-performance-protocol.h>
28 #include <dali/internal/network/common/socket-interface.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Adaptor
35 {
36 namespace
37 {
38 const float MICROSECONDS_TO_SECOND = 1e-6;
39 const char  UNKNOWN_CMD[]          = "Command or parameter invalid, type help for list of commands\n";
40
41 /**
42  * helper class to store data along with the automation callback.
43  */
44 class AutomationCallback : public CallbackBase
45 {
46 public:
47   /**
48    * instead of using templates, or having different callback classes for each callback
49    * we use a command id that decides which static function to call on the Automation class.
50    */
51   enum CommandId
52   {
53     UNKNOWN_COMMAND,
54     SET_PROPERTY,
55     DUMP_SCENE
56   };
57
58   AutomationCallback(unsigned int clientId, ClientSendDataInterface& sendDataInterface)
59   : CallbackBase(reinterpret_cast<void*>(this),
60                  NULL, // we get the dispatcher to call function directly
61                  reinterpret_cast<CallbackBase::Dispatcher>(&AutomationCallback::Dispatcher)),
62     mSendDataInterface(sendDataInterface),
63     mCommandId(UNKNOWN_COMMAND),
64     mClientId(clientId)
65   {
66   }
67
68   void AssignSetPropertyCommand(std::string setPropertyCommand)
69   {
70     mCommandId       = SET_PROPERTY;
71     mPropertyCommand = setPropertyCommand;
72   }
73   void AssignDumpSceneCommand()
74   {
75     mCommandId = DUMP_SCENE;
76   }
77
78   void RunCallback()
79   {
80     switch(mCommandId)
81     {
82       case SET_PROPERTY:
83       {
84         Automation::SetProperty(mPropertyCommand);
85         break;
86       }
87       case DUMP_SCENE:
88       {
89         Automation::DumpScene(mClientId, &mSendDataInterface);
90         break;
91       }
92       default:
93       {
94         DALI_ASSERT_DEBUG(0 && "Unknown command");
95         break;
96       }
97     }
98   }
99   static void Dispatcher(CallbackBase& base)
100   {
101     AutomationCallback& automationCallback(static_cast<AutomationCallback&>(base));
102     automationCallback.RunCallback();
103   }
104
105 private:
106   std::string              mPropertyCommand;   ///< property command
107   ClientSendDataInterface& mSendDataInterface; ///< Abstract client send data interface
108   CommandId                mCommandId;         ///< command id
109   const unsigned int       mClientId;          ///< client id
110 };
111
112 } // unnamed namespace
113
114 NetworkPerformanceClient::NetworkPerformanceClient(pthread_t*               thread,
115                                                    SocketInterface*         socket,
116                                                    unsigned int             clientId,
117                                                    ClientSendDataInterface& sendDataInterface,
118                                                    SocketFactoryInterface&  socketFactory)
119 : mThread(thread),
120   mSocket(socket),
121   mMarkerBitmask(PerformanceMarker::FILTERING_DISABLED),
122   mSendDataInterface(sendDataInterface),
123   mSocketFactoryInterface(socketFactory),
124   mClientId(clientId),
125   mConsoleClient(false)
126 {
127 }
128
129 NetworkPerformanceClient::~NetworkPerformanceClient()
130 {
131   if(mSocket->SocketIsOpen())
132   {
133     mSocket->CloseSocket();
134   }
135   mSocketFactoryInterface.DestroySocket(mSocket);
136 }
137
138 unsigned int NetworkPerformanceClient::GetId() const
139 {
140   return mClientId;
141 }
142
143 SocketInterface& NetworkPerformanceClient::GetSocket()
144 {
145   return *mSocket;
146 }
147
148 bool NetworkPerformanceClient::WriteSocket(const void* buffer, unsigned int bufferSizeInBytes)
149 {
150   return mSocket->Write(buffer, bufferSizeInBytes);
151 }
152
153 bool NetworkPerformanceClient::TransmitMarker(const PerformanceMarker& marker, const char* const description)
154 {
155   if(!marker.IsFilterEnabled(mMarkerBitmask))
156   {
157     return true;
158   }
159   if(mConsoleClient)
160   {
161     // write out the time stamp
162     char   buffer[64];
163     double usec = marker.GetTimeStamp().microseconds;
164     int    size = snprintf(buffer, sizeof(buffer), "%.6f (seconds), %s\n", usec * MICROSECONDS_TO_SECOND, description);
165
166     return mSocket->Write(buffer, size);
167   }
168
169   // todo serialize the data
170   return false;
171 }
172
173 void NetworkPerformanceClient::ExitSelect()
174 {
175   mSocket->ExitSelect();
176 }
177
178 pthread_t* NetworkPerformanceClient::GetThread()
179 {
180   return mThread;
181 }
182
183 void NetworkPerformanceClient::ProcessCommand(char* buffer, unsigned int bufferSizeInBytes)
184 {
185   // if connected via console, then strip off the carriage return, and switch to console mode
186   if(buffer[bufferSizeInBytes - 1] == '\n')
187   {
188     buffer[bufferSizeInBytes - 1] = 0;
189     mConsoleClient                = true;
190   }
191   unsigned int                   param(0);
192   std::string                    stringParam;
193   PerformanceProtocol::CommandId commandId(PerformanceProtocol::UNKNOWN_COMMAND);
194
195   bool ok = PerformanceProtocol::GetCommandId(buffer, bufferSizeInBytes, commandId, param, stringParam);
196   if(!ok)
197   {
198     WriteSocket(UNKNOWN_CMD, sizeof(UNKNOWN_CMD));
199     return;
200   }
201   std::string response;
202
203   switch(commandId)
204   {
205     case PerformanceProtocol::HELP_MESSAGE:
206     {
207       response = PerformanceProtocol::GetHelpMessage();
208       break;
209     }
210
211     case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
212     {
213       mMarkerBitmask = static_cast<PerformanceMarker::MarkerFilter>(param);
214       response       = "enable time marker ";
215       break;
216     }
217
218     case PerformanceProtocol::DUMP_SCENE_GRAPH:
219     {
220       // this needs to be run on the main thread, use the trigger event....
221       AutomationCallback* callback = new AutomationCallback(mClientId, mSendDataInterface);
222       callback->AssignDumpSceneCommand();
223
224       // create a trigger event that automatically deletes itself after the callback has run in the main thread
225       TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
226
227       // asynchronous call, the call back will be run sometime later on the main thread
228       interface->Trigger();
229       break;
230     }
231
232     case PerformanceProtocol::SET_PROPERTIES:
233     {
234       // this needs to be run on the main thread, use the trigger event....
235       AutomationCallback* callback = new AutomationCallback(mClientId, mSendDataInterface);
236       callback->AssignSetPropertyCommand(stringParam);
237
238       // create a trigger event that automatically deletes itself after the callback has run in the main thread
239       TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
240
241       // asynchronous call, the call back will be run sometime later on the main thread
242       interface->Trigger();
243       break;
244     }
245
246     case PerformanceProtocol::LIST_METRICS_AVAILABLE:
247     case PerformanceProtocol::ENABLE_METRIC:
248     case PerformanceProtocol::DISABLE_METRIC:
249     {
250       response = "Metrics currently not supported";
251       break;
252     }
253     default:
254     {
255       response = UNKNOWN_CMD;
256       break;
257     }
258   }
259   if(!response.empty())
260   {
261     // add a carriage return for console clients
262     if(mConsoleClient)
263     {
264       response += "\n";
265     }
266     WriteSocket(response.c_str(), response.length());
267   }
268 }
269
270 } // namespace Adaptor
271
272 } // namespace Internal
273
274 } // namespace Dali