7 #include "GaudiKernel/TypeNameString.h"
8 #include "GaudiKernel/IService.h"
9 #include "GaudiKernel/IRunable.h"
10 #include "GaudiKernel/IMessageSvc.h"
11 #include "GaudiKernel/IJobOptionsSvc.h"
13 #include "GaudiKernel/SmartIF.h"
14 #include "GaudiKernel/MsgStream.h"
15 #include "GaudiKernel/PropertyMgr.h"
16 #include "GaudiKernel/ObjectFactory.h"
18 #include "GaudiKernel/GaudiException.h"
19 #include "GaudiKernel/ThreadGaudi.h"
21 #include "GaudiKernel/StatusCode.h"
22 #include "GaudiKernel/Time.h"
23 #include "GaudiKernel/System.h"
25 #include "GaudiKernel/AppReturnCode.h"
27 #include "GaudiCoreSvcVersion.h"
37 static const char* s_eventloop =
"EventLoop";
38 static const char* s_runable =
"Runable";
40 #define ON_DEBUG if (UNLIKELY(m_outputLevel <= MSG::DEBUG))
41 #define ON_VERBOSE if (UNLIKELY(m_outputLevel <= MSG::VERBOSE))
59 m_managers[IService::interfaceID().id()] =
new ServiceManager(
this);
62 m_svcLocator = svcManager();
69 m_managers[IAlgorithm::interfaceID().id()] = algMgr;
72 m_propertyMgr->declareProperty(
"Go", m_SIGo = 0 );
73 m_propertyMgr->declareProperty(
"Exit", m_SIExit = 0 );
74 m_propertyMgr->declareProperty(
"Dlls", m_dllNameList );
75 m_propertyMgr->declareProperty(
"ExtSvc", m_extSvcNameList );
76 m_propertyMgr->declareProperty(
"CreateSvc", m_createSvcNameList );
77 m_propertyMgr->declareProperty(
"ExtSvcCreates", m_extSvcCreates=
true );
79 m_propertyMgr->declareProperty(
"SvcMapping", m_svcMapping );
80 m_propertyMgr->declareProperty(
"SvcOptMapping", m_svcOptMapping );
82 m_propertyMgr->declareProperty(
"TopAlg", m_topAlgNameList );
83 m_propertyMgr->declareProperty(
"OutStream", m_outStreamNameList );
84 m_propertyMgr->declareProperty(
"OutStreamType", m_outStreamType =
"OutputStream" );
85 m_propertyMgr->declareProperty(
"MessageSvcType",m_messageSvcType=
"MessageSvc" );
86 m_propertyMgr->declareProperty(
"JobOptionsSvcType",
87 m_jobOptionsSvcType =
"JobOptionsSvc" );
88 m_propertyMgr->declareProperty( s_runable, m_runableType =
"AppMgrRunable");
89 m_propertyMgr->declareProperty( s_eventloop, m_eventLoopMgr =
"EventLoopMgr");
91 m_propertyMgr->declareProperty(
"HistogramPersistency", m_histPersName=
"NONE");
94 m_propertyMgr->declareProperty(
"JobOptionsType", m_jobOptionsType =
"FILE");
95 m_propertyMgr->declareProperty(
"JobOptionsPath", m_jobOptionsPath =
"");
96 m_propertyMgr->declareProperty(
"JobOptionsPostAction", m_jobOptionsPostAction =
"");
97 m_propertyMgr->declareProperty(
"JobOptionsPreAction", m_jobOptionsPreAction =
"");
98 m_propertyMgr->declareProperty(
"EvtMax", m_evtMax = -1);
99 m_propertyMgr->declareProperty(
"EvtSel", m_evtsel );
100 m_propertyMgr->declareProperty(
"OutputLevel", m_outputLevel =
MSG::INFO);
102 m_propertyMgr->declareProperty(
"MultiThreadExtSvc", m_multiThreadSvcNameList);
103 m_propertyMgr->declareProperty(
"NoOfThreads", m_noOfEvtThreads = 0);
104 m_propertyMgr->declareProperty(
"AppName", m_appName =
"ApplicationMgr");
105 m_propertyMgr->declareProperty(
"AppVersion", m_appVersion =
"");
107 m_propertyMgr->declareProperty(
"AuditTools", m_auditTools =
false);
108 m_propertyMgr->declareProperty(
"AuditServices", m_auditSvcs =
false);
109 m_propertyMgr->declareProperty(
"AuditAlgorithms", m_auditAlgs =
false);
111 m_propertyMgr->declareProperty(
"ActivateHistory", m_actHistory =
false);
112 m_propertyMgr->declareProperty(
"StatusCodeCheck", m_codeCheck =
false);
114 m_propertyMgr->declareProperty(
"Environment", m_environment);
117 m_propertyMgr->declareProperty(
"InitializationLoopCheck", m_loopCheck =
true)
119 svcManager()->setLoopCheckEnabled(m_loopCheck);
122 m_propertyMgr->declareProperty
124 m_propertiesPrint =
false,
125 "Flag to activate the printout of properties" );
127 m_propertyMgr->declareProperty(
"PluginDebugLevel", m_pluginDebugLevel = 0 );
129 m_propertyMgr->declareProperty(
"StopOnSignal", m_stopOnSignal =
false,
130 "Flag to enable/disable the signal handler that schedule a stop of the event loop");
132 m_propertyMgr->declareProperty(
"StalledEventMonitoring", m_stalledEventMonitoring =
false,
133 "Flag to enable/disable the monitoring and reporting of stalled events");
136 "Return code of the application. Set internally in case of error conditions.");
138 m_propertyMgr->declareProperty(
"AlgTypeAliases", algMgr->
typeAliases(),
139 "Aliases of algorithm types, to replace an algorithm type for every instance");
149 m_svcMapping.insert(
std::end(m_svcMapping),
150 {
"EvtDataSvc/EventDataSvc",
151 "DetDataSvc/DetectorDataSvc",
152 "HistogramSvc/HistogramDataSvc",
153 "HbookCnv::PersSvc/HbookHistSvc",
154 "RootHistCnv::PersSvc/RootHistSvc",
155 "EvtPersistencySvc/EventPersistencySvc",
156 "DetPersistencySvc/DetectorPersistencySvc",
157 "HistogramPersistencySvc/HistogramPersistencySvc" } );
176 {
return serviceLocator()-> queryInterface ( iid , ppvi ) ; }
178 {
return svcManager() -> queryInterface ( iid , ppvi ) ; }
180 {
return algManager() -> queryInterface ( iid , ppvi ) ; }
182 {
return m_classManager -> queryInterface ( iid , ppvi ) ; }
184 {
return m_propertyMgr -> queryInterface ( iid , ppvi ) ; }
187 *ppvi =
reinterpret_cast<void*
>(m_messageSvc.get());
188 if (m_messageSvc) m_messageSvc->addRef();
216 fatal() <<
"Error creating JobOptionsSvc" <<
endmsg;
220 auto jobOptsIProp = jobsvc.as<
IProperty>();
221 if ( !jobOptsIProp ) {
222 fatal() <<
"Error locating JobOptionsSvc" <<
endmsg;
227 fatal() <<
"Error setting TYPE option in JobOptionsSvc" <<
endmsg;
234 fatal() <<
"Error setting JobOptionsPreAction option in JobOptionsSvc" <<
endmsg;
242 fatal() <<
"Error setting JobOptionsPostAction option in JobOptionsSvc" <<
endmsg;
250 fatal() <<
"Error setting PATH option in JobOptionsSvc" <<
endmsg;
254 else if (
isEnvSet(
"JOBOPTPATH") ) {
259 <<
"Error setting PATH option in JobOptionsSvc from env"
266 "../options/job.opts"));
269 <<
"Error setting PATH option in JobOptionsSvc to default"
274 jobOptsIProp.reset();
278 auto msgSvcIProp = msgsvc.as<
IProperty>();
282 sc = jobsvc->sysInitialize();
284 fatal() <<
"Error initializing JobOptionsSvc" <<
endmsg;
287 sc = msgsvc->sysInitialize();
289 fatal() <<
"Error initializing MessageSvc" <<
endmsg;
296 fatal() <<
"Error retrieving MessageSvc." <<
endmsg;
301 fatal() <<
"Error retrieving JobOptionsSvc." <<
endmsg;
321 <<
"configure: Invalid state \"" <<
m_state <<
"\"" <<
endmsg;
342 log <<
MSG::WARNING <<
"Problems getting my properties from JobOptionsSvc"
354 <<
"=================================================================="
355 <<
"=================================================================="
366 <<
"v" << GAUDICORESVC_MAJOR_VERSION
367 <<
"r" << GAUDICORESVC_MINOR_VERSION
368 #if GAUDICORESVC_PATCH_VERSION
369 <<
"p" << GAUDICORESVC_PATCH_VERSION
380 <<
"=================================================================="
381 <<
"=================================================================="
390 <<
"List of ALL properties of "
394 { log <<
"Property ['Name': Value] = " << *
property <<
endmsg ; }
402 log <<
MSG::FATAL <<
"Error adding StatusCodeSvc for multiple threads" <<
endmsg;
411 const std::string &
name = var.first;
412 const std::string &
value = var.second;
414 const MSG::Level lvl = (!old.empty() && (old !=
"UNKNOWN" ))
418 log << lvl <<
"Setting " << name <<
" = " << value <<
endmsg;
426 log <<
MSG::ERROR <<
"configure: declaring svc type:'" << j <<
"' failed." <<
endmsg;
433 log <<
MSG::ERROR <<
"configure: declaring svc type:'" << j <<
"' failed." <<
endmsg;
450 log <<
MSG::ERROR <<
"Failure during external service association" <<
endmsg;
456 log <<
MSG::ERROR <<
"Failure during multi thread service creation"
472 sc =
addMultiSvc(evtloop_item, ServiceManager::DEFAULT_SVC_PRIORITY*10);
483 <<
"\n Check option ApplicationMgr." << s_runable <<
endmsg;
490 <<
"\n Check option ApplicationMgr." << s_eventloop
491 <<
"\n No events will be processed." <<
endmsg;
515 sc =
addMultiSvc(
"HistorySvc",std::numeric_limits<int>::max());
517 log <<
MSG::FATAL <<
"Error adding HistorySvc for multiple threads"
524 log <<
MSG::INFO <<
"Application Manager Configured successfully" <<
endmsg;
541 std::string svcname(
"Gaudi::Utils::StopSignalHandler");
544 log <<
MSG::INFO <<
"Cannot instantiate " << svcname <<
"signals will be ignored" <<
endmsg;
550 std::string svcname(
"StalledEventMonitor");
553 log <<
MSG::INFO <<
"Cannot instantiate " << svcname <<
"signals will be ignored" <<
endmsg;
563 <<
"initialize: Invalid state \"" <<
m_state <<
"\"" <<
endmsg;
577 log <<
MSG::INFO <<
"Application Manager Initialized successfully" <<
endmsg;
611 log <<
MSG::INFO <<
"Application Manager Started successfully" <<
endmsg;
629 log <<
MSG::FATAL <<
"No event processing manager specified. Check option:"
668 log <<
MSG::INFO <<
"Application Manager Stopped successfully" <<
endmsg;
715 log <<
MSG::INFO <<
"Application Manager Finalized successfully" <<
endmsg;
743 log <<
MSG::INFO <<
"Application Manager Terminated successfully" <<
endmsg;
745 log <<
MSG::INFO <<
"Application Manager Terminated successfully with a user requested ScheduledStop" <<
endmsg;
766 log <<
MSG::ERROR <<
"Could not get the IService interface of the MessageSvc" <<
endmsg;
768 svc->sysFinalize().ignore();
774 log <<
MSG::ERROR <<
"Could not get the IService interface of the JobOptionsSvc" <<
endmsg;
776 svc->sysFinalize().ignore();
862 log <<
MSG::FATAL <<
"Application execution failed. Ending the job."
866 log <<
MSG::FATAL <<
"Application has no runable object. Check option:"
950 throw GaudiException(
"Cannot reinitialize application if not INITIALIZED or RUNNING",
1022 "MinimalEventLoopMgr::createSvcNameListHandler",
1032 auto it = theNames.begin();
1033 auto et = theNames.end();
1036 if( (result =
svcManager()->addService(item, ServiceManager::DEFAULT_SVC_PRIORITY) ).isFailure()) {
1038 log <<
MSG::ERROR <<
"decodeCreateSvcNameList: Cannot create service "
1043 log <<
MSG::DEBUG <<
"decodeCreateSvcNameList: Created service "
1057 "MinimalEventLoopMgr::extSvcNameListHandler",
1070 auto it = theNames.begin();
1071 auto et = theNames.end();
1075 if ( (result =
svcManager()->addService(item, ServiceManager::DEFAULT_SVC_PRIORITY)).isFailure()) {
1077 log <<
MSG::ERROR <<
"decodeExtSvcNameList: Cannot create service "
1082 item.
type()) ).isFailure()) {
1084 log <<
MSG::ERROR <<
"decodeExtSvcNameList: Cannot declare service "
1098 "MinimalEventLoopMgr::multiThreadSvcNameListHandler",
1111 for (
const auto& it : theNames ) {
1113 result =
addMultiSvc(item, ServiceManager::DEFAULT_SVC_PRIORITY);
1118 <<
"decodeMultiThreadSvcNameList: Cannot create service "
1124 <<
"decodeMultiThreadSvcNameList: created service "
1136 const std::string&
type) {
1142 log <<
MSG::ERROR <<
"declareMultiSvcType: Cannot declare service "
1143 << type <<
"/" << name <<
endmsg;
1146 log <<
MSG::VERBOSE <<
"declareMultiSvcType: declared service "
1147 << type <<
"/" << name <<
endmsg;
1154 log <<
MSG::ERROR <<
"declareMultiSvcType: Cannot declare service "
1155 << type <<
"/" << thrName <<
endmsg;
1158 log <<
MSG::VERBOSE <<
"declareMultiSvcType: declared service "
1159 << type <<
"/" << thrName <<
endmsg;
1177 log <<
MSG::ERROR <<
"addMultiSvc: Cannot add service "
1186 const std::string &
type = typeName.
type();
1189 if( result.isFailure() ) {
1190 log <<
MSG::ERROR <<
"addMultiSvc: Cannot add service "
1191 << type <<
"/" << thrName <<
endmsg;
1195 << type <<
"/" << thrName <<
endmsg;
1208 "MinimalEventLoopMgr::dllNameListHandler",
1223 std::vector<std::string> newList;
1224 std::map<std::string,unsigned int> dllInList, duplicateList;
1226 if ( 0 == dllInList[it] ) {
1227 newList.push_back(it);
1228 }
else { ++duplicateList[it]; }
1234 ON_DEBUG if ( !duplicateList.empty() ) {
1235 log <<
MSG::DEBUG <<
"Removed duplicate entries for modules : ";
1236 for (
auto it = duplicateList.begin(); it != duplicateList.end(); ++it ) {
1237 log << it->first <<
"(" << 1+it->second <<
")";
1238 if ( it != --duplicateList.end() ) log <<
", ";
1244 const std::vector<std::string>& theNames = newList;
1249 std::vector<std::string> successNames, failNames;
1250 for (
const auto& it : theNames) {
1255 failNames.push_back(it);
1259 successNames.push_back(it);
1265 if ( !successNames.empty() ) {
1266 log <<
MSG::INFO <<
"Successfully loaded modules : ";
1267 for (
auto it = successNames.begin(); it != successNames.end(); it++) {
1269 if( (it+1) != successNames.end()) log <<
", ";
1278 for (
auto it = failNames.begin(); it != failNames.end(); it++) {
1280 if( (it+1) != failNames.end()) log <<
", ";
1295 <<
"Updating Gaudi::PluginService::SetDebug(level) to level="
The ServiceManager class is in charge of the creation of concrete instances of Services.
void dllNameListHandler(Property &theProp)
Gaudi::StateMachine::State m_targetState
Internal State.
SimpleProperty< bool > BooleanProperty
The AlgorithmManager class is in charge of the creation of concrete instances of Algorithms.
StatusCode initialize() override
std::string m_jobOptionsType
Source type (e.g. dbase, file...)
constexpr int FinalizationFailure
Error codes for operation failures.
StringArrayProperty m_createSvcNameList
void createSvcNameListHandler(Property &)
virtual StatusCode addService(IService *svc, int prio=DEFAULT_SVC_PRIORITY)=0
Add a service to the "active" list of services of the factory.
Definition of the MsgStream class used to transmit messages.
virtual StatusCode stopRun()=0
Schedule a stop of the current event processing.
StringProperty m_messageSvcType
MessageSvc type.
virtual StatusCode run()=0
Run the class implementation.
Define general base for Gaudi exception.
StatusCode decodeDllNameList()
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
StatusCode loadModule(const std::string &module, bool fireIncident=true) override
SmartIF< IRunable > m_runable
Reference to the runable object.
MSG::Level level()
Retrieve output level.
virtual Property & declareUpdateHandler(std::function< void(Property &)> fun)
set new callback for update
int m_noOfEvtThreads
no of multiThreadSvc copies
bool m_codeCheck
Activate StatusCode checking.
static Time current(void)
Returns the current time.
bool isSuccess() const
Test for a status code of SUCCESS.
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
std::string m_jobOptionsPreAction
additional command to run on config
std::string m_appName
The name of the application.
IntegerProperty m_pluginDebugLevel
Debug level for the plugin system.
virtual StatusCode executeEvent(void *par=0)=0
Process single event.
static GAUDI_API void enableChecking()
std::vector< std::string > m_okDlls
names of successfully loaded dlls
std::map< std::string, std::string > m_environment
Environment variables to set.
State
Allowed states for classes implementing the state machine (ApplicationMgr, Algorithm, Service, AlgTool).
StringArrayProperty m_dllNameList
List of DDL's names.
StatusCode nextEvent(int maxevt) override
SmartIF< IJobOptionsSvc > m_jobOptionsSvc
Reference to JobOption service.
AlgTypeAliasesMap & typeAliases()
Property manager helper class.
virtual StatusCode declareSvcType(const std::string &svcname, const std::string &svctype)=0
Declare the type of the service to be used when crating a given service name.
bool isFailure() const
Test for a status code of FAILURE.
std::string m_jobOptionsPostAction
additional command to run on config
SmartIF< IEventProcessor > m_processingMgr
Reference to processing manager object.
StatusCode terminate() override
SmartIF< ISvcManager > & svcManager()
virtual StatusCode start()=0
Start (from INITIALIZED to RUNNING).
constexpr int ScheduledStop
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
int m_outputLevel
Message output level.
StatusCode addMultiSvc(const Gaudi::Utils::TypeNameString &typeName, int prio)
add one or more copies of svc type/name as determined by NoOfThreads
int m_evtMax
Number of events to be processed.
virtual StatusCode nextEvent(int maxevt)=0
Process the next maxevt events.
IntegerProperty m_returnCode
Property to record the error conditions occurring during the running.
void multiThreadSvcNameListHandler(Property &theProp)
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
#define DECLARE_OBJECT_FACTORY(x)
SimpleProperty< std::string > StringProperty
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Helper class to parse a string of format "type/name".
StatusCode executeRun(int evtmax) override
implementation of IEventProcessor::executeRun(int)
virtual StatusCode stop()=0
Stop (from RUNNING to INITIALIZED).
virtual StatusCode reinitialize()=0
Initialization (from INITIALIZED or RUNNING to INITIALIZED, via CONFIGURED).
std::string m_jobOptionsPath
The "file" to look for properties.
BooleanProperty m_extSvcCreates
LHCb or ATLAS defn of "ExtSvc".
General service interface definition.
VectorName m_svcMapping
Default mapping of services.
auto end(reverse_wrapper< T > &w)
SmartIF< ISvcLocator > m_svcLocator
Reference to its own service locator (must be instantiated prior to any service!) ...
This class is used for returning status codes from appropriate routines.
virtual SmartIF< IService > & createService(const Gaudi::Utils::TypeNameString &nametype)=0
Creates and instance of a service type that has been declared beforehand and assigns it a name...
Definition of the basic interface.
SimpleProperty< int > IntegerProperty
virtual StatusCode setMyProperties(const std::string &client, IProperty *me)=0
Override default properties of the calling client.
virtual StatusCode setProperty(const Property &p)=0
Set the property by property.
bool m_actHistory
Activate HistorySvc.
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
const std::vector< Property * > & getProperties() const override
get all properties
BooleanProperty m_loopCheck
For ServiceMgr initialization loop checking.
bool PyHelper() setProperty(IInterface *p, char *name, char *value)
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
GAUDI_API std::string getGaudiThreadIDfromID(int iCopy)
helper function to extract Gaudi Thread ID from thread copy number
StatusCode GoToState(Gaudi::StateMachine::State state, bool ignoreFailures=false)
Reach a state from current state (whichever it is) going through the correct transitions.
StatusCode finalize() override
virtual StatusCode initialize()=0
Initialization (from CONFIGURED to INITIALIZED).
const TYPE & value() const
explicit conversion
StringArrayProperty m_multiThreadSvcNameList
List of external services names for which we want a copy per evt thread.
VectorName m_svcOptMapping
Default mapping of services.
StatusCode executeEvent(void *par) override
implementation of IEventProcessor::executeEvent(void*)
The Application Manager class.
std::string m_runableType
Runable type.
StatusCode queryInterface(const InterfaceID &iid, void **pinterface) override
StatusCode decodeExtSvcNameList()
SmartIF< PropertyMgr > m_propertyMgr
Reference to Property Manager.
void initLoopCheckHndlr(Property &)
bool m_propertiesPrint
flag to activate the printout of properties
Property base class allowing Property* collections to be "homogeneous".
void SIGoHandler(Property &theProp)
GAUDIPS_API void SetDebug(int debugLevel)
Backward compatibility with Reflex.
SmartIF< DLLClassManager > m_classManager
Reference to the class manager.
StatusCode start() override
StatusCode restart() override
StatusCode configure() override
StringArrayProperty m_extSvcNameList
List of external services names.
StringProperty m_jobOptionsSvcType
JobOptionsSvc type.
virtual StatusCode restart()=0
Initialization (from RUNNING to RUNNING, via INITIALIZED).
StatusCode stopRun() override
implementation of IEventProcessor::stopRun()
const std::string & type() const
StatusCode decodeCreateSvcNameList()
void evtLoopPropertyHandler(Property &theProp)
virtual StatusCode finalize()=0
Finalize (from INITIALIZED to CONFIGURED).
BooleanProperty m_stalledEventMonitoring
Property to enable/disable the monitoring and reporting of stalled events (enabled by default)...
GAUDI_API const std::string & hostName()
Host name.
std::string m_eventLoopMgr
Processing manager type.
void SIExitHandler(Property &theProp)
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
StatusCode i_startup()
Internal startup routine.
StatusCode stop() override
static GAUDI_API void disableChecking()
StatusCode reinitialize() override
Gaudi::StateMachine::State m_state
Internal State.
Gaudi::StateMachine::State FSMState() const override
const std::string & name() const
virtual void setLoopCheckEnabled(bool en=true)=0
Set the value of the initialization loop check flag.
virtual StatusCode executeRun(int maxevt)=0
Process the maxevt events as a Run (beginRun() and endRun() called)
StatusCode run() override
std::string typeName(const std::type_info &typ)
StatusCode decodeMultiThreadSvcNameList()
The IProperty is the basic interface for all components which have properties that can be set or get...
SmartIF< IAlgManager > & algManager()
void extSvcNameListHandler(Property &theProp)
void pluginDebugPropertyHandler(Property &theProp)
BooleanProperty m_stopOnSignal
Property to enable/disable the "stop on signal" service (enabled by default).
static const InterfaceID & interfaceID()
Return an instance of InterfaceID identifying the interface.
const std::string & name() const override
std::string m_appVersion
The version of the application.
SmartIF< IMessageSvc > m_messageSvc
Reference to the message service.
virtual void setOutputLevel(int new_level)=0
Set new global output level threshold.
Gaudi::StateMachine::State targetFSMState() const override
std::string format(bool local, std::string spec="%c") const
Format the time using strftime.
StatusCode declareMultiSvcType(const std::string &name, const std::string &type)
declare one or more copies of svc type/name as determined by NoOfThreads