#
-# Copyright (c) 2017 Samsung Electronics Co., Ltd.
+# Copyright (c) 2018 Samsung Electronics Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
endif
-# $(adaptor_accessibility_tizen_common_src_files)
+endif
+
+
if MOBILE_PROFILE
LIBDALI_ADAPTOR_LA_SOURCES = \
$(adaptor_accessibility_common_src_files) \
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
+endif
+
endif
-# $(adaptor_accessibility_tizen_common_src_files)
if IVI_PROFILE
LIBDALI_ADAPTOR_LA_SOURCES = \
$(devel_api_text_abstraction_src_files) \
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
+endif
+
endif
-# $(adaptor_accessibility_tizen_common_src_files)
if TV_PROFILE
LIBDALI_ADAPTOR_LA_SOURCES = \
$(devel_api_text_abstraction_src_files) \
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
+endif
+
endif
if COMMON_PROFILE
$(devel_api_text_abstraction_src_files) \
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
+endif
+
endif
-# $(adaptor_accessibility_tizen_common_src_files)
if WEARABLE_PROFILE
$(devel_api_text_abstraction_src_files) \
$(static_libraries_glyphy_src_files) \
$(static_libraries_libunibreak_src_files)
+
+if ENABLE_NETWORK_LOGGING
+LIBDALI_ADAPTOR_LA_SOURCES += \
+ $(adaptor_performance_logging_src_files)
+endif
+
endif
+
# Package doc
package_doxy_dir = ../../../doc
include ../../../doc/file.list
--- /dev/null
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/automation.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <stdio.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/debug.h>
+
+
+namespace // un-named namespace
+{
+
+const unsigned int MAX_SET_PROPERTY_STRING_LENGTH = 256; ///< maximum length of a set property command
+
+class JsonPropertyValue
+{
+public:
+ JsonPropertyValue( const std::string& str )
+ {
+ std::size_t strLength = str.length();
+
+ mString.reserve( strLength );
+ for( std::size_t i = 0; i < strLength; ++i )
+ {
+ const char c = str[i];
+ if( (c != '[') && c != ']')
+ {
+ mString.push_back( c );
+ }
+ }
+
+ }
+ std::string GetString() const
+ {
+ return mString;
+ }
+ float GetFloat() const
+ {
+ return atof( mString.c_str() );
+ }
+ int GetInt()
+ {
+ return atoi( mString.c_str() );
+ }
+ bool GetBoolean()
+ {
+ return (GetInt() != 0);
+ }
+
+ Dali::Vector2 GetVector2()
+ {
+ Dali::Vector2 vec2;
+
+ int count = sscanf( mString.c_str(),"%f,%f",&vec2.x,&vec2.y );
+ if( count != 2 )
+ {
+ DALI_LOG_ERROR("Bad format\n");
+ }
+ return vec2;
+ }
+
+ Dali::Vector3 GetVector3()
+ {
+ Dali::Vector3 vec3;
+
+ int count = sscanf( mString.c_str(),"%f,%f,%f",&vec3.x,&vec3.y,&vec3.z );
+ if( count != 3 )
+ {
+ DALI_LOG_ERROR("Bad format\n");
+ }
+ return vec3;
+ }
+
+ Dali::Vector4 GetVector4()
+ {
+ Dali::Vector4 vec4;
+
+ int count = sscanf( mString.c_str(),"%f,%f,%f,%f", &vec4.x, &vec4.y, &vec4.z, &vec4.w );
+ if( count != 4 )
+ {
+ DALI_LOG_ERROR("Bad format\n");
+ }
+ return vec4;
+ }
+
+private:
+ std::string mString;
+
+};
+
+void SetProperty( Dali::Handle handle, int propertyId, JsonPropertyValue& propertyValue )
+{
+ Dali::Property::Type type = handle.GetPropertyType( propertyId );
+ switch( type )
+ {
+ case Dali::Property::FLOAT:
+ {
+ float val = propertyValue.GetFloat();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ case Dali::Property::INTEGER:
+ {
+ int val = propertyValue.GetInt();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ case Dali::Property::BOOLEAN:
+ {
+ bool val = propertyValue.GetBoolean();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ case Dali::Property::STRING:
+ {
+ std::string str = propertyValue.GetString();
+ handle.SetProperty( propertyId, Dali::Property::Value( str ) );
+ break;
+ }
+ case Dali::Property::VECTOR2:
+ {
+ Dali::Vector2 val = propertyValue.GetVector2();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ case Dali::Property::VECTOR3:
+ {
+ Dali::Vector3 val = propertyValue.GetVector3();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ case Dali::Property::VECTOR4:
+ {
+ Dali::Vector4 val = propertyValue.GetVector4();
+ handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+int SetProperties( const std::string& setPropertyMessage )
+{
+ std::istringstream iss( setPropertyMessage );
+ std::string token;
+ getline( iss, token, '|' ); // swallow command name
+ while( getline( iss, token, '|' ) )
+ {
+ std::string actorId, propName, propValue;
+ if( token.compare( "---" ) != 0 )
+ {
+ std::istringstream propss( token );
+ getline( propss, actorId, ';' );
+ getline( propss, propName, ';' );
+ getline( propss, propValue );
+
+ Dali::Actor root = Dali::Stage::GetCurrent().GetRootLayer();
+ int id = atoi( actorId.c_str() );
+ Dali::Actor a = root.FindChildById( id );
+ if( a )
+ {
+ // lookup by name for custom properties
+ int propId = a.GetPropertyIndex( propName );
+ if( propId > 0 )
+ {
+ JsonPropertyValue pv( propValue );
+ SetProperty( a, propId, pv );
+ }
+
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+}; // un-named namespace
+
+inline std::string Quote( const std::string& in )
+{
+ return (std::string( "\"" ) + in + std::string( "\"" ));
+}
+
+template<class T>
+std::string ToString( T i )
+{
+ std::stringstream ss;
+ std::string s;
+ ss << i;
+ s = ss.str();
+
+ return s;
+}
+
+
+// currently rotations are output in Euler format ( may change)
+void AppendPropertyNameAndValue( Dali::Handle handle, int propertyIndex, std::ostringstream& outputStream)
+{
+ // get the property name and the value as a string
+ std::string propertyName( handle.GetPropertyName( propertyIndex ) );
+
+ // Apply quotes around the property name
+ outputStream << "\"" << propertyName << "\"" << ",";
+
+ // Convert value to a string
+ std::ostringstream valueStream;
+ Dali::Property::Value value = handle.GetProperty( propertyIndex );
+ valueStream << value;
+ std::string valueString = valueStream.str();
+
+ if( value.GetType() == Dali::Property::STRING )
+ {
+ // Escape the string (to ensure valid json)
+ // Write out quotes, escapes and control characters using unicode syntax \uXXXX
+ std::ostringstream escapedValue;
+ for( std::string::iterator c = valueString.begin() ; c != valueString.end(); ++c )
+ {
+ if( *c == '"' )
+ {
+ escapedValue << "\\\"";
+ }
+ else if( *c == '\\' )
+ {
+ escapedValue << "\\\\";
+ }
+ else if( '\x00' <= *c && *c <= '\x1f' )
+ {
+ escapedValue << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(*c);
+ }
+ else
+ {
+ escapedValue << *c;
+ }
+ }
+
+ valueString = escapedValue.str();
+ }
+
+ outputStream << "\"" << valueString << "\"";
+}
+
+bool ExcludeProperty( int propIndex )
+{
+ return (propIndex == Dali::Actor::Property::NAME ||
+
+ // all of these are repeat properties of values in vectors....
+ // We don't really need these in the UI
+ propIndex == Dali::Actor::Property::ANCHOR_POINT_X || propIndex == Dali::Actor::Property::ANCHOR_POINT_Y || propIndex == Dali::Actor::Property::ANCHOR_POINT_Z || propIndex == Dali::Actor::Property::PARENT_ORIGIN_X
+ || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Y || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Z || propIndex == Dali::Actor::Property::COLOR_RED || propIndex == Dali::Actor::Property::COLOR_GREEN
+ || propIndex == Dali::Actor::Property::COLOR_BLUE || propIndex == Dali::Actor::Property::COLOR_ALPHA|| propIndex == Dali::Actor::Property::POSITION_X || propIndex == Dali::Actor::Property::POSITION_Y
+ || propIndex == Dali::Actor::Property::POSITION_Z|| propIndex == Dali::Actor::Property::SIZE_WIDTH|| propIndex == Dali::Actor::Property::SIZE_HEIGHT || propIndex == Dali::Actor::Property::SCALE_X || propIndex == Dali::Actor::Property::SCALE_Y
+ || propIndex == Dali::Actor::Property::SCALE_Z || propIndex == Dali::Actor::Property::SIZE_DEPTH);
+}
+
+std::string DumpJson( Dali::Actor actor, int level )
+{
+ // All the information about this actor
+ std::ostringstream msg;
+ msg << "{ " << Quote( "Name" ) << " : " << Quote( actor.GetName() ) << ", " << Quote( "level" ) << " : " << level << ", " << Quote( "id" ) << " : " << actor.GetId() << ", " << Quote( "IsVisible" )
+ << " : " << actor.IsVisible() << ", " << Quote( "IsSensitive" ) << " : " << actor.IsSensitive();
+
+ msg << ", " << Quote( "properties" ) << ": [ ";
+
+ Dali::Property::IndexContainer indices;
+ actor.GetPropertyIndices( indices );
+
+ Dali::Property::IndexContainer::Iterator iter = indices.Begin();
+ int numCustom = 0;
+ for( ; iter != indices.End() ; iter++ )
+ {
+ int i = *iter;
+ if( !ExcludeProperty( i ) )
+ {
+ if( numCustom++ != 0 )
+ {
+ msg << ", ";
+ }
+ msg << "[";
+
+ AppendPropertyNameAndValue( actor, i,msg );
+
+ msg << "]";
+ }
+ }
+ msg << "]";
+ msg << ", " << Quote( "children" ) << " : [ ";
+
+ // Recursively dump all the children as well
+ for( unsigned int i = 0 ; i < actor.GetChildCount() ; ++i )
+ {
+ if( i )
+ {
+ msg << " , ";
+ }
+ msg << DumpJson( actor.GetChildAt( i ), level + 1 );
+ }
+ msg << "] }";
+
+ return msg.str();
+}
+
+std::string GetActorTree()
+{
+ Dali::Actor actor = Dali::Stage::GetCurrent().GetRootLayer();
+ std::string str = DumpJson( actor, 0 );
+ return str;
+}
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Automation
+{
+
+void SetProperty( const std::string& message )
+{
+ // check the set property length is within range
+ if( message.length() > MAX_SET_PROPERTY_STRING_LENGTH )
+ {
+ DALI_LOG_ERROR("SetProperty message length too long, size = %ul\n", message.length());
+ return;
+ }
+
+ SetProperties( message );
+}
+
+void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData )
+{
+ char buf[32];
+ std::string json = GetActorTree();
+ int length = json.length();
+ snprintf( buf, 32, "%d\n", length );
+ std::string header( buf );
+ json = buf + json;
+ sendData->SendData( json.c_str(), json.length(), clientId );
+}
+
+} // namespace Automation
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-client.h>
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/internal/network/common/socket-interface.h>
+#include <dali/internal/network/common/network-performance-protocol.h>
+#include <dali/internal/network/common/automation.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float MICROSECONDS_TO_SECOND = 1e-6;
+const char UNKNOWN_CMD[]= "Command or parameter invalid, type help for list of commands\n";
+
+
+/**
+ * helper class to store data along with the automation callback.
+ */
+class AutomationCallback: public CallbackBase
+{
+public:
+
+ /**
+ * instead of using templates, or having different callback classes for each callback
+ * we use a command id that decides which static function to call on the Automation class.
+ */
+ enum CommandId
+ {
+ UNKNOWN_COMMAND,
+ SET_PROPERTY,
+ DUMP_SCENE
+ };
+
+ AutomationCallback( unsigned int clientId, ClientSendDataInterface& sendDataInterface )
+ :CallbackBase( reinterpret_cast< void* >( this ),
+ NULL, // we get the dispatcher to call function directly
+ reinterpret_cast< CallbackBase::Dispatcher>( &AutomationCallback::Dispatcher) ),
+ mSendDataInterface( sendDataInterface ),
+ mCommandId( UNKNOWN_COMMAND ),
+ mClientId( clientId )
+ {}
+
+ void AssignSetPropertyCommand( std::string setPropertyCommand )
+ {
+ mCommandId = SET_PROPERTY;
+ mPropertyCommand = setPropertyCommand;
+ }
+ void AssignDumpSceneCommand()
+ {
+ mCommandId = DUMP_SCENE;
+ }
+
+ void RunCallback()
+ {
+ switch( mCommandId )
+ {
+ case SET_PROPERTY:
+ {
+ Automation::SetProperty( mPropertyCommand );
+ break;
+ }
+ case DUMP_SCENE:
+ {
+ Automation::DumpScene( mClientId, &mSendDataInterface);
+ break;
+ }
+ default:
+ {
+ DALI_ASSERT_DEBUG( 0 && "Unknown command");
+ break;
+ }
+ }
+ }
+ static void Dispatcher( CallbackBase& base )
+ {
+ AutomationCallback& automationCallback( static_cast< AutomationCallback& >( base) );
+ automationCallback.RunCallback();
+ }
+
+private:
+
+ std::string mPropertyCommand; ///< property command
+ ClientSendDataInterface& mSendDataInterface; ///< Abstract client send data interface
+ CommandId mCommandId; ///< command id
+ const unsigned int mClientId; ///< client id
+};
+
+} // unnamed namespace
+
+NetworkPerformanceClient::NetworkPerformanceClient( pthread_t* thread,
+ SocketInterface *socket,
+ unsigned int clientId,
+ TriggerEventFactoryInterface& triggerEventFactory,
+ ClientSendDataInterface& sendDataInterface,
+ SocketFactoryInterface& socketFactory )
+: mThread( thread ),
+ mSocket( socket ),
+ mMarkerBitmask( PerformanceMarker::FILTERING_DISABLED ),
+ mTriggerEventFactory( triggerEventFactory ),
+ mSendDataInterface( sendDataInterface ),
+ mSocketFactoryInterface( socketFactory ),
+ mClientId( clientId ),
+ mConsoleClient(false)
+{
+
+}
+
+NetworkPerformanceClient::~NetworkPerformanceClient()
+{
+ if( mSocket->SocketIsOpen() )
+ {
+ mSocket->CloseSocket();
+ }
+ mSocketFactoryInterface.DestroySocket( mSocket );
+}
+
+unsigned int NetworkPerformanceClient::GetId() const
+{
+ return mClientId;
+}
+
+SocketInterface& NetworkPerformanceClient::GetSocket()
+{
+ return *mSocket;
+}
+
+bool NetworkPerformanceClient::WriteSocket( const void* buffer, unsigned int bufferSizeInBytes )
+{
+ return mSocket->Write( buffer, bufferSizeInBytes );
+}
+
+bool NetworkPerformanceClient::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+ if( ! marker.IsFilterEnabled( mMarkerBitmask ) )
+ {
+ return true;
+ }
+ if( mConsoleClient )
+ {
+ // write out the time stamp
+ char buffer[64];
+ double usec = marker.GetTimeStamp().microseconds;
+ int size = snprintf( buffer, sizeof(buffer),"%.6f (seconds), %s\n",
+ usec * MICROSECONDS_TO_SECOND,
+ description );
+
+ return mSocket->Write( buffer, size );
+
+ }
+
+
+ // todo serialize the data
+ return false;
+}
+
+void NetworkPerformanceClient::ExitSelect()
+{
+ mSocket->ExitSelect();
+}
+
+pthread_t* NetworkPerformanceClient::GetThread()
+{
+ return mThread;
+}
+
+void NetworkPerformanceClient::ProcessCommand( char* buffer, unsigned int bufferSizeInBytes )
+{
+ // if connected via console, then strip off the carriage return, and switch to console mode
+ if( buffer[ bufferSizeInBytes - 1] == '\n')
+ {
+ buffer[ bufferSizeInBytes - 1] = 0;
+ mConsoleClient = true;
+ }
+ unsigned int param(0);
+ std::string stringParam;
+ PerformanceProtocol::CommandId commandId( PerformanceProtocol::UNKNOWN_COMMAND );
+
+ bool ok = PerformanceProtocol::GetCommandId( buffer, bufferSizeInBytes, commandId, param, stringParam );
+ if( !ok )
+ {
+ WriteSocket( UNKNOWN_CMD, sizeof(UNKNOWN_CMD) );
+ return;
+ }
+ std::string response;
+
+ switch( commandId )
+ {
+ case PerformanceProtocol::HELP_MESSAGE:
+ {
+ response = PerformanceProtocol::GetHelpMessage();
+ break;
+ }
+
+ case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
+ {
+ mMarkerBitmask = static_cast< PerformanceMarker::MarkerFilter >( param );
+ response = "enable time marker ";
+ break;
+ }
+
+ case PerformanceProtocol::DUMP_SCENE_GRAPH:
+ {
+ // this needs to be run on the main thread, use the trigger event....
+ AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+ callback->AssignDumpSceneCommand();
+
+ // create a trigger event that automatically deletes itself after the callback has run in the main thread
+ TriggerEventInterface *interface = mTriggerEventFactory.CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+ // asynchronous call, the call back will be run sometime later on the main thread
+ interface->Trigger();
+ break;
+ }
+
+ case PerformanceProtocol::SET_PROPERTIES:
+ {
+ // this needs to be run on the main thread, use the trigger event....
+ AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+ callback->AssignSetPropertyCommand( stringParam );
+
+ // create a trigger event that automatically deletes itself after the callback has run in the main thread
+ TriggerEventInterface *interface = mTriggerEventFactory.CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+ // asynchronous call, the call back will be run sometime later on the main thread
+ interface->Trigger();
+ break;
+ }
+
+ case PerformanceProtocol::LIST_METRICS_AVAILABLE:
+ case PerformanceProtocol::ENABLE_METRIC:
+ case PerformanceProtocol::DISABLE_METRIC:
+ {
+ response="Metrics currently not supported";
+ break;
+ }
+ default:
+ {
+ response = UNKNOWN_CMD;
+ break;
+ }
+ }
+ if( ! response.empty() )
+ {
+ // add a carriage return for console clients
+ if( mConsoleClient )
+ {
+ response+="\n";
+ }
+ WriteSocket( response.c_str(), response.length() );
+ }
+}
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-protocol.h>
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace Dali
+{
+
+namespace PerformanceProtocol
+{
+
+namespace
+{
+
+/**
+ * Command parameter type
+ */
+enum PARAMETER_TYPE
+{
+ NO_PARAMS,
+ UNSIGNED_INT,
+ STRING
+};
+
+/**
+ * Command information structure
+ */
+struct CommandInfo
+{
+ CommandId cmdId;
+ CommandString cmdString;
+ PARAMETER_TYPE paramType;
+};
+
+/**
+ * Command lookup table
+ */
+CommandInfo CommandLookup[]=
+{
+ { HELP_MESSAGE , "help" ,NO_PARAMS },
+ { ENABLE_METRIC , "enable_metric" ,UNSIGNED_INT },
+ { DISABLE_METRIC , "disable_metric" ,UNSIGNED_INT },
+ { LIST_METRICS_AVAILABLE , "list_metrics" ,NO_PARAMS },
+ { ENABLE_TIME_MARKER_BIT_MASK, "set_marker", UNSIGNED_INT },
+ { DUMP_SCENE_GRAPH , "dump_scene" ,NO_PARAMS },
+ { SET_PROPERTIES , "set_properties" ,STRING },
+ { UNKNOWN_COMMAND , "unknown" ,NO_PARAMS }
+};
+const unsigned int CommandLookupLength = sizeof( CommandLookup ) /sizeof( CommandInfo );
+
+#define GREEN "\033[01;32m"
+#define NORMAL "\e[m"
+#define PARAM "\033[22;32m"
+#define YELLOW "\033[01;33m"
+
+const char* const helpMsg =
+ YELLOW
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ " Dali performance console \n"
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" NORMAL
+ GREEN " list_metrics " NORMAL " - list available metrics\n"
+ GREEN " enable_metric " PARAM " metricId" NORMAL " - enable a metric \n"
+ GREEN " disable_metric " PARAM " metricId" NORMAL " - disable a metric\n\n"
+ GREEN " set_marker " PARAM " value " NORMAL "-output Dali markers\n"
+ " : Bit 0 = V_SYNC (1)\n"
+ " : Bit 1 = Update task (2)\n"
+ " : Bit 2 = Render task (4) \n"
+ " : Bit 3 = Event Processing task (8)\n"
+ " : Bit 4 = SwapBuffers (16)\n"
+ " : Bit 5 = Life cycle events (32)\n"
+ " : Bit 6 = Resource event (64)\n"
+ "\n"
+ GREEN " set_properties " NORMAL " - set an actor property command. Format:\n\n"
+ GREEN " set_properties " PARAM "|ActorIndex;Property;Value|" NORMAL ", e.g: \n"
+ GREEN " set_properties " PARAM "|178;Size;[ 144.0, 144.0, 144.0 ]|178;Color;[ 1.0, 1,0, 1.0 ]|\n"
+ "\n"
+ GREEN " dump_scene" NORMAL " - dump the current scene in json format\n";
+
+} // un-named namespace
+
+bool GetCommandId( const char* const commandString, unsigned int lengthInBytes, CommandId& commandId, unsigned int& intParam, std::string& stringParam )
+{
+ commandId = UNKNOWN_COMMAND;
+ intParam = 0;
+
+ // the command list is small so just do a O(n) search for the commandID.
+ for( unsigned int i = 0 ; i < CommandLookupLength; ++i )
+ {
+ if( strncmp( commandString, CommandLookup[i].cmdString ,strlen(CommandLookup[i].cmdString )) == 0 )
+ {
+ commandId = CommandLookup[i].cmdId;
+
+ // if the command has a parameter read it
+ if( CommandLookup[i].paramType == UNSIGNED_INT)
+ {
+ int count = sscanf(commandString,"%*s %d",&intParam);
+ if( count != 1 )
+ {
+ // missing parameter
+ return false;
+ }
+ }
+ else if (CommandLookup[i].paramType == STRING )
+ {
+ char* charParam( NULL );
+ // allocates the character array
+ int count = sscanf(commandString,"%*s %ms",&charParam);
+ if( count != 1 )
+ {
+ // missing parameter
+ return false;
+ }
+ stringParam = std::string( charParam);
+ free(charParam);
+ }
+ return true;
+ }
+ }
+ // not found
+ return false;
+}
+
+bool GetCommandString( CommandId commandId, CommandString& commandString )
+{
+ for( unsigned int i = 0; i < CommandLookupLength; ++i)
+ {
+ if( CommandLookup[ i ].cmdId == commandId )
+ {
+ strncpy( commandString, CommandLookup[ i ].cmdString, strlen(CommandLookup[ i ].cmdString) );
+ return true;
+ }
+ }
+ strncpy( commandString, CommandLookup[ UNKNOWN_COMMAND ].cmdString, MAX_COMMAND_STRING_LENGTH);
+ return false;
+}
+
+const char* const GetHelpMessage()
+{
+ return helpMsg;
+}
+
+
+} // namespace PerformanceProtocol
+
+} // namespace Dali
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-server.h>
+
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-marker.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // un-named namespace
+{
+const unsigned int SERVER_PORT = 3031;
+const unsigned int MAXIMUM_PORTS_TO_TRY = 10; ///< if port in use, try up to SERVER_PORT + 10
+const unsigned int CONNECTION_BACKLOG = 2; ///< maximum length of the queue of pending connections.
+const unsigned int SOCKET_READ_BUFFER_SIZE = 4096;
+typedef Vector< NetworkPerformanceClient*> ClientList;
+
+/**
+ * POD passed to client thread on startup
+ */
+struct ClientThreadInfo
+{
+ NetworkPerformanceServer* server;
+ NetworkPerformanceClient* client;
+};
+}
+
+NetworkPerformanceServer::NetworkPerformanceServer( AdaptorInternalServices& adaptorServices,
+ const EnvironmentOptions& logOptions )
+: mTriggerEventFactory( adaptorServices.GetTriggerEventFactoryInterface() ),
+ mSocketFactory( adaptorServices.GetSocketFactoryInterface() ),
+ mLogOptions( logOptions ),
+ mServerThread( 0 ),
+ mListeningSocket( NULL ),
+ mClientUniqueId( 0 ),
+ mClientCount( 0 ),
+ mLogFunctionInstalled( false )
+{
+}
+
+NetworkPerformanceServer::~NetworkPerformanceServer()
+{
+ Stop();
+
+ if( mLogFunctionInstalled )
+ {
+ mLogOptions.UnInstallLogFunction();
+ }
+}
+
+void NetworkPerformanceServer::Start()
+{
+ // start a thread to listen for incoming connection requests
+ if (! mServerThread )
+ {
+ if( mListeningSocket )
+ {
+ mSocketFactory.DestroySocket( mListeningSocket );
+ }
+ mListeningSocket = mSocketFactory.NewSocket( SocketInterface::TCP);
+ mListeningSocket->ReuseAddress( true );
+
+ bool bound = false;
+ unsigned int basePort = 0;
+
+ // try a small range of ports, so if multiple Dali apps are running you can select
+ // which one to connect to
+ while( !bound && ( basePort < MAXIMUM_PORTS_TO_TRY ))
+ {
+ bound = mListeningSocket->Bind( SERVER_PORT + basePort );
+ if( !bound )
+ {
+ basePort++;
+ }
+ }
+ if(!bound )
+ {
+ DALI_LOG_ERROR("Failed to bind to a port \n");
+ return;
+ }
+
+ mListeningSocket->Listen( CONNECTION_BACKLOG );
+
+ // start a thread which will block waiting for new connections
+ int error = pthread_create( &mServerThread, NULL, ConnectionListenerFunc, this );
+ DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+ Dali::Integration::Log::LogMessage(Integration::Log::DebugInfo, "~~~ NetworkPerformanceServer started on port %d ~~~ \n", SERVER_PORT + basePort);
+
+ }
+}
+void NetworkPerformanceServer::Stop()
+{
+ if( !mServerThread )
+ {
+ return;
+ }
+
+ if( mListeningSocket )
+ {
+ // close the server thread to prevent any new connections
+ mListeningSocket->ExitSelect();
+ }
+
+ // wait for the thread to exit.
+ void* exitValue;
+ pthread_join( mServerThread, &exitValue );
+
+ if( mListeningSocket )
+ {
+ // close the socket
+ mListeningSocket->CloseSocket();
+ }
+
+ mSocketFactory.DestroySocket( mListeningSocket );
+
+ mListeningSocket = NULL;
+
+ // this will tell all client threads to quit
+ StopClients();
+
+}
+
+bool NetworkPerformanceServer::IsRunning() const
+{
+ if (mServerThread )
+ {
+ return true;
+ }
+ return false;
+}
+
+void NetworkPerformanceServer::ClientThread( NetworkPerformanceClient* client )
+{
+ mClientCount++;
+
+ SocketInterface& socket( client->GetSocket() );
+
+ for( ;; )
+ {
+ SocketInterface::SelectReturn ret = socket.Select();
+
+ if( ret == SocketInterface::DATA_AVAILABLE )
+ {
+ // Read
+ char buffer[ SOCKET_READ_BUFFER_SIZE ];
+ unsigned int bytesRead;
+
+ bool ok = socket.Read( buffer, sizeof( buffer ) , bytesRead);
+ if( ok && ( bytesRead > 0) )
+ {
+ client->ProcessCommand( buffer, bytesRead );
+ }
+ else // if bytesRead == 0, then client closed connection, if ok == false then an error
+ {
+ DeleteClient( client );
+ return;
+ }
+ }
+ else // ret == QUIT or ERROR
+ {
+ DeleteClient( client);
+ return;
+ }
+ }
+}
+
+void NetworkPerformanceServer::ConnectionListener()
+{
+ // install Dali logging function for this thread
+ if( !mLogFunctionInstalled )
+ {
+ mLogOptions.InstallLogFunction();
+ mLogFunctionInstalled = true;
+ }
+
+ for( ;; )
+ {
+ // this will block, waiting for a client to connect
+ // or for mListeningSocket->ExitSelect() to be called
+
+ SocketInterface::SelectReturn ret = mListeningSocket->Select();
+
+ if( ret == SocketInterface::DATA_AVAILABLE )
+ {
+ SocketInterface* clientSocket = mListeningSocket->Accept();
+
+ // new connection made, spawn a thread to handle it
+ pthread_t* clientThread = new pthread_t();
+
+ NetworkPerformanceClient* client = AddClient( clientSocket, clientThread );
+
+ ClientThreadInfo* info = new ClientThreadInfo;
+ info->client = client;
+ info->server = this;
+
+ int error = pthread_create( clientThread, NULL, ClientThreadFunc, info );
+ DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+ }
+ else // ret == SocketInterface::QUIT or SocketInterface::ERROR
+ {
+ return;
+ }
+ }
+}
+
+void* NetworkPerformanceServer::ClientThreadFunc( void* data )
+{
+ ClientThreadInfo* info = static_cast<ClientThreadInfo*>( data );
+ info->server->ClientThread( info->client );
+ delete info;
+ return NULL;
+}
+
+NetworkPerformanceClient* NetworkPerformanceServer::AddClient( SocketInterface* clientSocket, pthread_t* clientThread )
+{
+ // This function is only called from the listening thread
+ NetworkPerformanceClient* client= new NetworkPerformanceClient( clientThread,
+ clientSocket,
+ mClientUniqueId++,
+ mTriggerEventFactory,
+ *this,
+ mSocketFactory);
+
+ // protect the mClients list which can be accessed from multiple threads.
+ Mutex::ScopedLock lock( mClientListMutex );
+
+ mClients.PushBack( client );
+
+ return client;
+}
+
+void NetworkPerformanceServer::DeleteClient( NetworkPerformanceClient* client )
+{
+ // protect the mClients list while modifying
+ Mutex::ScopedLock lock( mClientListMutex );
+
+ // remove from the list, and delete it
+ for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+ {
+ if( (*iter) == client )
+ {
+ mClients.Erase( iter );
+ delete client;
+
+ // if there server is shutting down, it waits for client count to hit zero
+ mClientCount--;
+
+ return;
+ }
+ }
+}
+
+void NetworkPerformanceServer::SendData( const char* const data, unsigned int bufferSizeInBytes,unsigned int clientId )
+{
+ if( ! mClientCount )
+ {
+ return;
+ }
+
+ // prevent clients been added / deleted while transmiting data
+ Mutex::ScopedLock lock( mClientListMutex );
+
+ for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+ {
+ NetworkPerformanceClient* client = (*iter);
+ if( client->GetId() == clientId )
+ {
+ client->WriteSocket(data ,bufferSizeInBytes);
+ return;
+ }
+ }
+}
+
+void NetworkPerformanceServer::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+ if( ! IsRunning() )
+ {
+ return;
+ }
+ // prevent clients been added / deleted while transmiting data
+ Mutex::ScopedLock lock( mClientListMutex );
+
+ for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+ {
+ NetworkPerformanceClient* client = (*iter);
+ client->TransmitMarker( marker, description );
+ }
+}
+
+
+void NetworkPerformanceServer::StopClients()
+{
+ // prevent clients been added / deleted while stopping all clients
+ Mutex::ScopedLock lock( mClientListMutex );
+
+ for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+ {
+ NetworkPerformanceClient* client = (*iter);
+ // stop the client from waiting for new commands, and exit from it's thread
+ client->ExitSelect();
+ }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
# module: network, backend: common
adaptor_network_common_src_files=\
${adaptor_network_dir}/common/socket-factory.cpp \
- ${adaptor_network_dir}/common/socket-impl.cpp
\ No newline at end of file
+ ${adaptor_network_dir}/common/socket-impl.cpp
+
+adaptor_performance_logging_src_files=\
+ $(adaptor_network_dir)/common/network-performance-protocol.cpp \
+ $(adaptor_network_dir)/common/network-performance-client.cpp \
+ $(adaptor_network_dir)/common/network-performance-server.cpp \
+ $(adaptor_network_dir)/common/automation.cpp
#define __DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H__
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#if defined(NETWORK_LOGGING_ENABLED)
NetworkPerformanceServer mNetworkServer; ///< network server
- bool mNetworkControlEnabled; ///< Whether network control is enabled
+ bool mNetworkControlEnabled; ///< Whether network control is enabled
#endif
StatContextManager mStatContextManager; ///< Stat context manager
# module: window-system, backend: tizen
adaptor_window_system_tizen_src_files=\
- ${adaptor_window_system_dir}/tizen/display-connection-impl-tizen.cpp
+ ${adaptor_window_system_dir}/tizen/native-render-surface-tizen.cpp
# module: window-system, backend: tizen-mobile
adaptor_window_system_tizen_mobile_src_files=\
${adaptor_window_system_dir}/tizen-mobile/native-render-surface-factory-mobile.cpp
-# module: window-system, backend: tizen
-adaptor_window_system_tizen_src_files=\
- ${adaptor_window_system_dir}/tizen/native-render-surface-tizen.cpp
-
# module: window-system, backend: tizen-wayland
adaptor_window_system_tizen_wayland_src_files=\
${adaptor_window_system_dir}/tizen-wayland/display-connection-factory-ecore-wl.cpp \
+++ /dev/null
-/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/window-system/common/display-connection-impl.h>
-
-// EXTERNAL_HEADERS
-#include <tbm_bufmgr.h>
-#include <dali/integration-api/debug.h>
-
-// INTERNAL HEADERS
-#include <dali/integration-api/wayland/native-render-surface.h>
-#include <dali/internal/graphics/gles20/egl-implementation.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-EGLNativeDisplayType DisplayConnection::GetNativeDisplay()
-{
- return reinterpret_cast< EGLNativeDisplayType >( tbm_bufmgr_init( -1 ) );
-}
-
-void DisplayConnection::ReleaseNativeDisplay()
-{
- if( mDisplay )
- {
- tbm_bufmgr_deinit( reinterpret_cast< tbm_bufmgr >( mDisplay ) );
- }
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali