__pycache__/__init__.cpython-36.opt-1.pyc000064400000000265147205076570014120 0ustar003 s__pycache__/__init__.cpython-36.pyc000064400000000265147205076570013161 0ustar003 s__pycache__/application.cpython-36.opt-1.pyc000064400000017516147205076570014673 0ustar003 .handler_wrapper)signal)r'r,r+r-r()r+r,r)_handle_signal?szApplication._handle_signalcCs:|jtj|jj|jtj|jj|jtj|jjdS)N)r/r.SIGHUPr$ZsighupSIGINTZ terminateSIGTERM)r'r(r(r)r%EszApplication._init_signalscCs6|jdk rtdtjj|||||_tj|jdS)Nz&DBus interface is already initialized.)rr rZdbusZ DBusExporterregister_exporter)r'Zbus_nameZ object_nameZinterface_name namespacer(r(r)attach_to_dbusJs zApplication.attach_to_dbuscCsj|jdk rtdtjj|jjtj|jjtj |jjtj |jj tj |jj tj |_tj|jdS)Nz-Unix socket interface is already initialized.)rr rZ unix_socketZUnixSocketExporterrr!rZCFG_UNIX_SOCKET_PATHZCFG_UNIX_SOCKET_SIGNAL_PATHSZCFG_UNIX_SOCKET_OWNERSHIPZget_intZCFG_UNIX_SOCKET_PERMISIONSZ#CFG_UNIX_SOCKET_CONNECTIONS_BACKLOGr3)r'r(r(r)attach_to_unix_socketQs    z!Application.attach_to_unix_socketcCstj|jdS)N)rZregister_objectr$)r'r(r(r)register_controller\szApplication.register_controllerc Cstj|tj|gggtj\}}}t|dkrBtj|tdtj|d}tj|t|dkrltdytj d|d}Wntj k rtdYnX|dkrtd d S) z| Wait till the child signalizes that the initialization is complete by writing some uninteresting data into the pipe. r z=Cannot daemonize, timeout when waiting for the child process.rz:Cannot daemonize, no response from child process received.?z?Cannot daemonize, invalid response from child process received.Tz0Cannot daemonize, child process reports failure.N) rcloseselectrZDAEMONIZE_PARENT_TIMEOUTlenr readstructunpackerror)r' parent_in_fd child_out_fdZ read_readyZdropZresponsevalr(r(r)_daemonize_parent_s      zApplication._daemonize_parentcCs||_|jyltjj|j}tjj|s4tj|tjtj|jtj tj Btj Bdd}|j dtj WdQRXWn>ttfk r}ztjd|jt|fWYdd}~XnXdS)Niwz%dzcannot write the PID to %s: %s)r&_delete_pid_filerpathdirnameexistsmakedirsfdopenopenO_CREATO_TRUNCO_WRONLYwritegetpidOSErrorIOErrorrcriticalstr)r'pid_fileZdir_namefr@r(r(r)write_pid_filexs  ( zApplication.write_pid_filecCs^tjj|jrZytj|jWn:tk rX}ztjd|jt|fWYdd}~XnXdS)Nz&cannot remove existing PID file %s, %s) rrGrIr&unlinkrRrZwarningrU)r'r@r(r(r)rFs zApplication._delete_pid_filecCs*tj|tjdtjtjdytj}|dkrBtjdWn^tk r}zBt j dt |t j dd}tj||tj|tdWYdd}~XnXtdd }tj|jtjjtj|jtjjtj|jtjj|j|t jd t j dd }tj||tj|dS) zy Finishes daemonizing process, writes a PID file and signalizes to the parent that the initialization is complete. /rz"cannot daemonize, fork() error: %sr9Fz'Cannot daemonize, second fork() failed.Nz /dev/nullzw+zsuccessfully daemonizedT)rr:chdirsetsidumaskforksysexitrRrrTrUr>packrPr rLdup2filenostdinstdoutstderrrXdebug)r'rVrArBpidr@rCfdr(r(r)_daemonize_childs.           zApplication._daemonize_childcCstj}y tj}WnFtk rZ}z*tj|dtj|dtdWYdd}~XnXy2|dkr||j|tjdn|j |f|Wn"|dkrn tjdYnXdS)z Daemonizes the application. In case of failure, TunedException is raised in the parent process. If the operation is successfull, the main process is terminated and only child process returns from this method. rr z Cannot daemonize, fork() failed.N) rpiper^rRr:r rDr_r`rj)r'rVZparent_child_fdsZ child_pidr@r(r(r) daemonizes    zApplication.daemonizecCs|jS)N)r#)r'r(r(r)r szApplication.daemoncCs|jS)N)r$)r'r(r(r)r szApplication.controllercCsj|r|jjtjd|jjtjtjs0tjd|jj }|jjtjtjrTt j |j dk rf|j |S)NTzrUsing one shot no daemon mode, most of the functionality will be not available, it can be changed in global config)rsetrZ CFG_DAEMONrZCFG_DEF_DAEMONrwarnr$runrstopr&rF)r'r resultr(r(r)ros   zApplication.run)NN)__name__ __module__ __qualname__r*r/r%r5r6r7rDrZPID_FILErXrFrjrlpropertyr r ror(r(r(r)rs +  "  )rrrrrrrrZtuned.exceptionsr Z tuned.logsZ tuned.versionr r r.rr_r;r>Z tuned.constsrZtuned.utils.global_configr Zlogsr!r__all__objectrr(r(r(r)s$      __pycache__/application.cpython-36.pyc000064400000017516147205076570013734 0ustar003 .handler_wrapper)signal)r'r,r+r-r()r+r,r)_handle_signal?szApplication._handle_signalcCs:|jtj|jj|jtj|jj|jtj|jjdS)N)r/r.SIGHUPr$ZsighupSIGINTZ terminateSIGTERM)r'r(r(r)r%EszApplication._init_signalscCs6|jdk rtdtjj|||||_tj|jdS)Nz&DBus interface is already initialized.)rr rZdbusZ DBusExporterregister_exporter)r'Zbus_nameZ object_nameZinterface_name namespacer(r(r)attach_to_dbusJs zApplication.attach_to_dbuscCsj|jdk rtdtjj|jjtj|jjtj |jjtj |jj tj |jj tj |_tj|jdS)Nz-Unix socket interface is already initialized.)rr rZ unix_socketZUnixSocketExporterrr!rZCFG_UNIX_SOCKET_PATHZCFG_UNIX_SOCKET_SIGNAL_PATHSZCFG_UNIX_SOCKET_OWNERSHIPZget_intZCFG_UNIX_SOCKET_PERMISIONSZ#CFG_UNIX_SOCKET_CONNECTIONS_BACKLOGr3)r'r(r(r)attach_to_unix_socketQs    z!Application.attach_to_unix_socketcCstj|jdS)N)rZregister_objectr$)r'r(r(r)register_controller\szApplication.register_controllerc Cstj|tj|gggtj\}}}t|dkrBtj|tdtj|d}tj|t|dkrltdytj d|d}Wntj k rtdYnX|dkrtd d S) z| Wait till the child signalizes that the initialization is complete by writing some uninteresting data into the pipe. r z=Cannot daemonize, timeout when waiting for the child process.rz:Cannot daemonize, no response from child process received.?z?Cannot daemonize, invalid response from child process received.Tz0Cannot daemonize, child process reports failure.N) rcloseselectrZDAEMONIZE_PARENT_TIMEOUTlenr readstructunpackerror)r' parent_in_fd child_out_fdZ read_readyZdropZresponsevalr(r(r)_daemonize_parent_s      zApplication._daemonize_parentcCs||_|jyltjj|j}tjj|s4tj|tjtj|jtj tj Btj Bdd}|j dtj WdQRXWn>ttfk r}ztjd|jt|fWYdd}~XnXdS)Niwz%dzcannot write the PID to %s: %s)r&_delete_pid_filerpathdirnameexistsmakedirsfdopenopenO_CREATO_TRUNCO_WRONLYwritegetpidOSErrorIOErrorrcriticalstr)r'pid_fileZdir_namefr@r(r(r)write_pid_filexs  ( zApplication.write_pid_filecCs^tjj|jrZytj|jWn:tk rX}ztjd|jt|fWYdd}~XnXdS)Nz&cannot remove existing PID file %s, %s) rrGrIr&unlinkrRrZwarningrU)r'r@r(r(r)rFs zApplication._delete_pid_filecCs*tj|tjdtjtjdytj}|dkrBtjdWn^tk r}zBt j dt |t j dd}tj||tj|tdWYdd}~XnXtdd }tj|jtjjtj|jtjjtj|jtjj|j|t jd t j dd }tj||tj|dS) zy Finishes daemonizing process, writes a PID file and signalizes to the parent that the initialization is complete. /rz"cannot daemonize, fork() error: %sr9Fz'Cannot daemonize, second fork() failed.Nz /dev/nullzw+zsuccessfully daemonizedT)rr:chdirsetsidumaskforksysexitrRrrTrUr>packrPr rLdup2filenostdinstdoutstderrrXdebug)r'rVrArBpidr@rCfdr(r(r)_daemonize_childs.           zApplication._daemonize_childcCstj}y tj}WnFtk rZ}z*tj|dtj|dtdWYdd}~XnXy2|dkr||j|tjdn|j |f|Wn"|dkrn tjdYnXdS)z Daemonizes the application. In case of failure, TunedException is raised in the parent process. If the operation is successfull, the main process is terminated and only child process returns from this method. rr z Cannot daemonize, fork() failed.N) rpiper^rRr:r rDr_r`rj)r'rVZparent_child_fdsZ child_pidr@r(r(r) daemonizes    zApplication.daemonizecCs|jS)N)r#)r'r(r(r)r szApplication.daemoncCs|jS)N)r$)r'r(r(r)r szApplication.controllercCsj|r|jjtjd|jjtjtjs0tjd|jj }|jjtjtjrTt j |j dk rf|j |S)NTzrUsing one shot no daemon mode, most of the functionality will be not available, it can be changed in global config)rsetrZ CFG_DAEMONrZCFG_DEF_DAEMONrwarnr$runrstopr&rF)r'r resultr(r(r)ros   zApplication.run)NN)__name__ __module__ __qualname__r*r/r%r5r6r7rDrZPID_FILErXrFrjrlpropertyr r ror(r(r(r)rs +  "  )rrrrrrrrZtuned.exceptionsr Z tuned.logsZ tuned.versionr r r.rr_r;r>Z tuned.constsrZtuned.utils.global_configr Zlogsr!r__all__objectrr(r(r(r)s$      __pycache__/controller.cpython-36.opt-1.pyc000064400000031757147205076570014556 0ustar003 d?Zej dddgd@dAZ ej ddBdhdCdDZ!ej dddidEdFZ"ej ddGdjdHdIZ#ej dddkdJdKZ$ej dLd#dldMdNZ%ej ddOdmdPdQZ&ej ddRdndSdTZ'Z(S)orz Controller's purpose is to keep the program running, start/stop the tuning, and export the controller interface (currently only over D-Bus). cs8tt|j||_||_tj|_t|_ t |_ dS)N) superrr_daemon_global_configr ZEvent _terminater_cmdr _timer_store)r daemonZ global_config) __class__r r r+s  zController.__init__cCsxtjd|j}|jjtjtj}| r6|r6tj|rb|j j x|j j |j ds`tj qFWtjd|jdS)z1 Controller main loop. The call is blocking. zstarting controllerzterminating controllerN)loginfostartrget_boolconsts CFG_DAEMONCFG_DEF_DAEMONrrrrwaitZ period_checkstop)r resr r r r run3s     zController.runcCs|jjdS)N)rset)r r r r terminateFszController.terminatecCs0|jjjs,|jjj|js,|jjjdS)N)rZ_sighup_processingZis_setr.reloadr)r r r r sighupIs  zController.sighupZsbscCsdS)Nr )r profile_nameresultZerrstrr r r profile_changedOszController.profile_changedcCstjj||jj|dS)N)tunedlogslog_capture_finishrr)r rr r r _log_capture_abortXs zController._log_capture_abortZiisNcCsf|dkr dStjj|}|dkr$dS|dkrVtj||j|gd}|jj|||j|dkrbdS|S)Nr)args) r5r6log_capture_startr ZTimerr8rrr%)r Z log_levelZtimeoutcallerrrr r r r<\s zController.log_capture_startcCs4|dkr dStjj|}|jj||dkr0dS|S)Nr:)r5r6r7rr)r rr=r,r r r r7js   zController.log_capture_finishr:bcCsD|dkr dS|jjtjtjr:|jjr,dS|jjs:dS|jjS)Nr:FT) rr&r'r(r)r is_running is_enabledr%)r r=r r r r%rs  zController.startFcCs,|jjsd}n|jj|d}|jj|S)NT)profile_switch)rr?r+rr)r rAr,r r r _stop}s   zController._stopcCs|dkr dS|jddS)Nr:F)rA)rB)r r=r r r r+szController.stopcCsp|dkr dS|jjr*|jdd}|s*dSy|jjWn.tk rf}ztjd|dSd}~XnX|jS)Nr:FT)rAzFailed to reload TuneD: %s)rr?rBZreload_profile_configrr#errorr%)r r=Zstop_oker r r r0s  zController.reloadcCs|jj}d}d}d}zy$|r,|jjdd|jj||Wnftjjk r}zFd}t|}|r|jjj |krt j d|d}nt j d|WYdd}~XnXWd|r|rt j d|n|st j d|jjX||fS) NOKTF)rAz@Failed to reapply profile '%s'. Did it change on disk and break?zFailed to apply profile '%s'z>Applying previously applied (possibly out-dated) profile '%s'.z$Applying previously applied profile.)rr?r+Z set_profiler5 exceptionsrstrprofilenamer#rCwarnr$r%)r r2manualZ was_runningmsgsuccessZreapplyrDr r r _switch_profiles, $  zController._switch_profilez(bs)cCs|dkr dS|j|dS)Nr:F UnauthorizedT)FrO)rN)r r2r=r r r switch_profileszController.switch_profilecCs |dkr dS|j}|j|dS)Nr:FrO)FrO)recommend_profilerN)r r=r2r r r auto_profileszController.auto_profilecCs*|dkr dS|jjdk r"|jjjSdSdS)Nr:)rrHrI)r r=r r r active_profiles   zController.active_profilez(ss)cCs|dkr dS|jj}|dkrpy"|jj\}}|dkr<|dk }Wn0tk rn}zd}t|}||fSd}~XnX|rztjntj}|dfS)Nr:unknownrO)rTrO) rrKrZget_active_profilerrGr'ZACTIVE_PROFILE_MANUALZACTIVE_PROFILE_AUTO)r r=rKrHrDmoderCr r r profile_modes zController.profile_modecCs|dkr dS|jjpdS)Nr:)rpost_loaded_profile)r r=r r r rWszController.post_loaded_profilecCsB|dkr dS|jjr |jj|jjr>|jjddddddS)Nr:FT)Zsave_instantly)rr?r+r@Zset_all_profiles)r r=r r r disables    zController.disablecCs|dkr dS|jjS)Nr:F)rr?)r r=r r r r?szController.is_runningascCs|dkr gS|jjjjS)Nr:)rprofile_loaderprofile_locatorZget_known_names)r r=r r r profilesszController.profilesza(ss)cCs|dkr gS|jjjjS)Nr:)rrZr[Zget_known_names_summary)r r=r r r profiles2szController.profiles2z(bsss)cCsP|dkrtddddS|dks&|dkr.|j}t|jjjj|tjtjgdgS)Nr:F) tuplerSrrZr[Zget_profile_attrsr'ZPROFILE_ATTR_SUMMARYZPROFILE_ATTR_DESCRIPTION)r r2r=r r r profile_infos zController.profile_infocCs|dkr dS|jjjS)Nr:)rZprofile_recommenderZ recommend)r r=r r r rQszController.recommend_profilecCs|dkr dS|jjddS)Nr:F)ignore_missing)rverify_profile)r r=r r r raszController.verify_profilecCs|dkr dS|jjddS)Nr:FT)r`)rra)r r=r r r verify_profile_ignore_missingsz(Controller.verify_profile_ignore_missingz a{sa{ss}}cCsz|dkr dSi}xd|jjD]V}|jjddjddd}|j}i||<x$|jD]\}}t||||<qVWqW|S)zuReturn dictionary with accesible plugins Return: dictionary -- {plugin_name: {parameter_name: default_value}} r:F.r"_)rget_all_pluginsrsplitZ_get_config_optionsitemsrG)r r=ZpluginsZ plugin_class plugin_nameZ conf_optionskeyvalr r r rfszController.get_all_pluginscCs|dkr dS|jjt|S)z"Return docstring of plugin's classr:F)rget_plugin_documentationrG)r rir=r r r rl,sz#Controller.get_plugin_documentationza{ss}cCs|dkr dS|jjt|S)zReturn dictionary with plugin's parameters and their hints Parameters: plugin_name -- name of plugin Return: dictionary -- {parameter_name: hint} r:F)rget_plugin_hintsrG)r rir=r r r rm3s zController.get_plugin_hintscCs6|dkr dS|jjr2|jjjr2|jjjj|dSdS)zAllows to dynamically add sockets to send signals to Parameters: path -- path to socket to register for sending signals Return: bool -- True on success r:FT)rZ _applicationZ_unix_socket_exporterZregister_signal_path)r pathr=r r r register_socket_signal_pathAs z&Controller.register_socket_signal_pathZssc Csb|dkr d Sd}x2|jjjD]$}|j|krtjd|jd}PqW|sbd|}tj|d|fSt|jj |}tjd|jt |fx|jjjD]}|j |@} t | r|| 8}tj dt | |j|jf|jj|jjkrd |j|jjt | |j|jjf}tj|d|fS|jj|| |jj|| qWt |r^d t |}tj |d|fSd S)Nr:FrOzFound instance '%s'.TzInstance '%s' not foundz-Instance '%s' trying to acquire devices '%s'.z8Moving devices '%s' from instance '%s' to instance '%s'.ztTarget instance '%s' is of type '%s', but devices '%s' are currently handled by instance '%s' which is of type '%s'.z2Ignoring devices not handled by any instance '%s'.rE)FrO)TrE)r _unit_manager instancesrIr#debugrCr.rZ devstr2devsrGprocessed_deviceslenr$pluginZ_remove_devices_nocheckZ_add_devices_nocheck) r Zdevices instance_namer=foundZinstance_targetretsZdevsinstanceZ devs_movingr r r instance_acquire_devicesUsB        z#Controller.instance_acquire_devicesz (bsa(ss))cs|dkrddgfSdkrF|jjkrFd}tj|d|gfStdd|jjj}dkrttfdd|}dd tt d d|fS) aReturn a list of active instances of a plugin or all active instances Parameters: plugin_name -- name of the plugin or an empty string Return: bool -- True on success string -- error message or "OK" list of string pairs -- [(instance_name, plugin_name)] r:FrOzPlugin '%s' does not existcSs|jS)N)Zactive)ryr r r sz*Controller.get_instances..cs |jjkS)N)rurI)ry)rir r r{sTrEcSs|j|jjfS)N)rIru)ryr r r r{s) rfkeysr#rCfilterrrprqlistmap)r rir=rxrqr )rir get_instancesys    zController.get_instancesz(bsas)cCs`|dkrddgfSx0|jjjD]"}|j|krddtt|jfSqWd|}tj|d|gfS)zReturn a list of devices assigned to an instance Parameters: instance_name -- name of the instance Return: bool -- True on success string -- error message or "OK" list of strings -- device names r:FrOTrEzInstance '%s' not found) rrprqrIsortedr~rsr#rC)r rvr=ryrxr r r instance_get_devicess    zController.instance_get_devices)N)N)N)F)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N))rrr__doc__rr-r/r1rsignalr4r8Zexportr<r7r%rBr+r0rNrPrRrSrVrWrXr?r\r]r_rQrarbrfrlrmrorzrr __classcell__r r )r!r r%sv                                             #   )r5rZ tuned.logsZtuned.exceptionsrr Z tuned.constsr'Ztuned.utils.commandsr__all__r6getr#objectrZ interfacesZExportableInterfacerr r r r s     __pycache__/controller.cpython-36.pyc000064400000031757147205076570013617 0ustar003 d?Zej dddgd@dAZ ej ddBdhdCdDZ!ej dddidEdFZ"ej ddGdjdHdIZ#ej dddkdJdKZ$ej dLd#dldMdNZ%ej ddOdmdPdQZ&ej ddRdndSdTZ'Z(S)orz Controller's purpose is to keep the program running, start/stop the tuning, and export the controller interface (currently only over D-Bus). cs8tt|j||_||_tj|_t|_ t |_ dS)N) superrr_daemon_global_configr ZEvent _terminater_cmdr _timer_store)r daemonZ global_config) __class__r r r+s  zController.__init__cCsxtjd|j}|jjtjtj}| r6|r6tj|rb|j j x|j j |j ds`tj qFWtjd|jdS)z1 Controller main loop. The call is blocking. zstarting controllerzterminating controllerN)loginfostartrget_boolconsts CFG_DAEMONCFG_DEF_DAEMONrrrrwaitZ period_checkstop)r resr r r r run3s     zController.runcCs|jjdS)N)rset)r r r r terminateFszController.terminatecCs0|jjjs,|jjj|js,|jjjdS)N)rZ_sighup_processingZis_setr.reloadr)r r r r sighupIs  zController.sighupZsbscCsdS)Nr )r profile_nameresultZerrstrr r r profile_changedOszController.profile_changedcCstjj||jj|dS)N)tunedlogslog_capture_finishrr)r rr r r _log_capture_abortXs zController._log_capture_abortZiisNcCsf|dkr dStjj|}|dkr$dS|dkrVtj||j|gd}|jj|||j|dkrbdS|S)Nr)args) r5r6log_capture_startr ZTimerr8rrr%)r Z log_levelZtimeoutcallerrrr r r r<\s zController.log_capture_startcCs4|dkr dStjj|}|jj||dkr0dS|S)Nr:)r5r6r7rr)r rr=r,r r r r7js   zController.log_capture_finishr:bcCsD|dkr dS|jjtjtjr:|jjr,dS|jjs:dS|jjS)Nr:FT) rr&r'r(r)r is_running is_enabledr%)r r=r r r r%rs  zController.startFcCs,|jjsd}n|jj|d}|jj|S)NT)profile_switch)rr?r+rr)r rAr,r r r _stop}s   zController._stopcCs|dkr dS|jddS)Nr:F)rA)rB)r r=r r r r+szController.stopcCsp|dkr dS|jjr*|jdd}|s*dSy|jjWn.tk rf}ztjd|dSd}~XnX|jS)Nr:FT)rAzFailed to reload TuneD: %s)rr?rBZreload_profile_configrr#errorr%)r r=Zstop_oker r r r0s  zController.reloadcCs|jj}d}d}d}zy$|r,|jjdd|jj||Wnftjjk r}zFd}t|}|r|jjj |krt j d|d}nt j d|WYdd}~XnXWd|r|rt j d|n|st j d|jjX||fS) NOKTF)rAz@Failed to reapply profile '%s'. Did it change on disk and break?zFailed to apply profile '%s'z>Applying previously applied (possibly out-dated) profile '%s'.z$Applying previously applied profile.)rr?r+Z set_profiler5 exceptionsrstrprofilenamer#rCwarnr$r%)r r2manualZ was_runningmsgsuccessZreapplyrDr r r _switch_profiles, $  zController._switch_profilez(bs)cCs|dkr dS|j|dS)Nr:F UnauthorizedT)FrO)rN)r r2r=r r r switch_profileszController.switch_profilecCs |dkr dS|j}|j|dS)Nr:FrO)FrO)recommend_profilerN)r r=r2r r r auto_profileszController.auto_profilecCs*|dkr dS|jjdk r"|jjjSdSdS)Nr:)rrHrI)r r=r r r active_profiles   zController.active_profilez(ss)cCs|dkr dS|jj}|dkrpy"|jj\}}|dkr<|dk }Wn0tk rn}zd}t|}||fSd}~XnX|rztjntj}|dfS)Nr:unknownrO)rTrO) rrKrZget_active_profilerrGr'ZACTIVE_PROFILE_MANUALZACTIVE_PROFILE_AUTO)r r=rKrHrDmoderCr r r profile_modes zController.profile_modecCs|dkr dS|jjpdS)Nr:)rpost_loaded_profile)r r=r r r rWszController.post_loaded_profilecCsB|dkr dS|jjr |jj|jjr>|jjddddddS)Nr:FT)Zsave_instantly)rr?r+r@Zset_all_profiles)r r=r r r disables    zController.disablecCs|dkr dS|jjS)Nr:F)rr?)r r=r r r r?szController.is_runningascCs|dkr gS|jjjjS)Nr:)rprofile_loaderprofile_locatorZget_known_names)r r=r r r profilesszController.profilesza(ss)cCs|dkr gS|jjjjS)Nr:)rrZr[Zget_known_names_summary)r r=r r r profiles2szController.profiles2z(bsss)cCsP|dkrtddddS|dks&|dkr.|j}t|jjjj|tjtjgdgS)Nr:F) tuplerSrrZr[Zget_profile_attrsr'ZPROFILE_ATTR_SUMMARYZPROFILE_ATTR_DESCRIPTION)r r2r=r r r profile_infos zController.profile_infocCs|dkr dS|jjjS)Nr:)rZprofile_recommenderZ recommend)r r=r r r rQszController.recommend_profilecCs|dkr dS|jjddS)Nr:F)ignore_missing)rverify_profile)r r=r r r raszController.verify_profilecCs|dkr dS|jjddS)Nr:FT)r`)rra)r r=r r r verify_profile_ignore_missingsz(Controller.verify_profile_ignore_missingz a{sa{ss}}cCsz|dkr dSi}xd|jjD]V}|jjddjddd}|j}i||<x$|jD]\}}t||||<qVWqW|S)zuReturn dictionary with accesible plugins Return: dictionary -- {plugin_name: {parameter_name: default_value}} r:F.r"_)rget_all_pluginsrsplitZ_get_config_optionsitemsrG)r r=ZpluginsZ plugin_class plugin_nameZ conf_optionskeyvalr r r rfszController.get_all_pluginscCs|dkr dS|jjt|S)z"Return docstring of plugin's classr:F)rget_plugin_documentationrG)r rir=r r r rl,sz#Controller.get_plugin_documentationza{ss}cCs|dkr dS|jjt|S)zReturn dictionary with plugin's parameters and their hints Parameters: plugin_name -- name of plugin Return: dictionary -- {parameter_name: hint} r:F)rget_plugin_hintsrG)r rir=r r r rm3s zController.get_plugin_hintscCs6|dkr dS|jjr2|jjjr2|jjjj|dSdS)zAllows to dynamically add sockets to send signals to Parameters: path -- path to socket to register for sending signals Return: bool -- True on success r:FT)rZ _applicationZ_unix_socket_exporterZregister_signal_path)r pathr=r r r register_socket_signal_pathAs z&Controller.register_socket_signal_pathZssc Csb|dkr d Sd}x2|jjjD]$}|j|krtjd|jd}PqW|sbd|}tj|d|fSt|jj |}tjd|jt |fx|jjjD]}|j |@} t | r|| 8}tj dt | |j|jf|jj|jjkrd |j|jjt | |j|jjf}tj|d|fS|jj|| |jj|| qWt |r^d t |}tj |d|fSd S)Nr:FrOzFound instance '%s'.TzInstance '%s' not foundz-Instance '%s' trying to acquire devices '%s'.z8Moving devices '%s' from instance '%s' to instance '%s'.ztTarget instance '%s' is of type '%s', but devices '%s' are currently handled by instance '%s' which is of type '%s'.z2Ignoring devices not handled by any instance '%s'.rE)FrO)TrE)r _unit_manager instancesrIr#debugrCr.rZ devstr2devsrGprocessed_deviceslenr$pluginZ_remove_devices_nocheckZ_add_devices_nocheck) r Zdevices instance_namer=foundZinstance_targetretsZdevsinstanceZ devs_movingr r r instance_acquire_devicesUsB        z#Controller.instance_acquire_devicesz (bsa(ss))cs|dkrddgfSdkrF|jjkrFd}tj|d|gfStdd|jjj}dkrttfdd|}dd tt d d|fS) aReturn a list of active instances of a plugin or all active instances Parameters: plugin_name -- name of the plugin or an empty string Return: bool -- True on success string -- error message or "OK" list of string pairs -- [(instance_name, plugin_name)] r:FrOzPlugin '%s' does not existcSs|jS)N)Zactive)ryr r r sz*Controller.get_instances..cs |jjkS)N)rurI)ry)rir r r{sTrEcSs|j|jjfS)N)rIru)ryr r r r{s) rfkeysr#rCfilterrrprqlistmap)r rir=rxrqr )rir get_instancesys    zController.get_instancesz(bsas)cCs`|dkrddgfSx0|jjjD]"}|j|krddtt|jfSqWd|}tj|d|gfS)zReturn a list of devices assigned to an instance Parameters: instance_name -- name of the instance Return: bool -- True on success string -- error message or "OK" list of strings -- device names r:FrOTrEzInstance '%s' not found) rrprqrIsortedr~rsr#rC)r rvr=ryrxr r r instance_get_devicess    zController.instance_get_devices)N)N)N)F)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N)N))rrr__doc__rr-r/r1rsignalr4r8Zexportr<r7r%rBr+r0rNrPrRrSrVrWrXr?r\r]r_rQrarbrfrlrmrorzrr __classcell__r r )r!r r%sv                                             #   )r5rZ tuned.logsZtuned.exceptionsrr Z tuned.constsr'Ztuned.utils.commandsr__all__r6getr#objectrZ interfacesZExportableInterfacerr r r r s     __pycache__/daemon.cpython-36.opt-1.pyc000064400000025261147205076570013627 0ustar003 DaemonNcCstjdtj|_ttj|_ttj|_ tj |_ d|_ tj |_|dk r|jtjtj|_t|jtjtj|_t|jtjtj|_ |jtjtj |_ |jtjtj|_ |jtjtj |_||_|jdkrttj|_|j dkrd|_ n|j |jkr|j|_ |j |j|_tjd|j|j rJtjdtjd|j|j|jft|j d|_||_||_|jt |_!y|j"|Wn2t#k r}ztj$d |WYdd}~XnXdS) Nzinitializing daemonTrFz$using sleep interval of %d second(s)z8dynamic tuning is enabled (can be overridden by plugins)zFusing update interval of %d second(s) (%d times of the sleep interval))Z is_hardcodedz:Cannot set initial profile. No tunings will be enabled: %s)%logdebugconstsZCFG_DEF_DAEMON_daemonintZCFG_DEF_SLEEP_INTERVAL_sleep_intervalZCFG_DEF_UPDATE_INTERVALZ_update_intervalZCFG_DEF_DYNAMIC_TUNING_dynamic_tuningZ_recommend_commandZCFG_DEF_ROLLBACK _rollbackZget_boolZ CFG_DAEMONgetZCFG_SLEEP_INTERVALZCFG_UPDATE_INTERVALZCFG_DYNAMIC_TUNINGZCFG_RECOMMEND_COMMANDZCFG_DEF_RECOMMEND_COMMAND CFG_ROLLBACK _application _sleep_cyclesinfor_profile_recommender _unit_manager_profile_loader _init_threadsr_cmd _init_profilererror)selfZ unit_managerprofile_loader profile_namesconfigZ applicationer!/usr/lib/python3.6/daemon.py__init__sF        zDaemon.__init__cCsFd|_tj|_tj|_tj|_tj|_|jjtj|_dS)N) _thread threadingZEvent _terminate_terminate_profile_switch _not_used_sighup_processingset_profile_applied)rr!r!r"r7s     zDaemon._init_threadscCs|jddS)zARead configuration files again and load profile according to themN)r)rr!r!r"reload_profile_configCszDaemon.reload_profile_configcCsd}|jj}|dkrP|j\}}|dkrrd}|r<|d7}n|d7}tj|n"|dkrr|rhtjdn tjdd|_d|_g|_d|_|j |||dS)NTz.No profile is preset, running in manual mode. z(Only post-loaded profile will be enabledzNo profile will be enabled.) rZget_post_loaded_profile_get_startup_profilerr_profile_manual_active_profiles_post_loaded_profileset_all_profiles)rrmanualpost_loaded_profilemsgr!r!r"rGs&      zDaemon._init_profilecCs|pd}|j}|jr2tjd|j||jg}x:|D]2}||jjjkr8d|}|j|d|t|q8Wy.|r|j j ||_ nd|_ ||_ |j|_ WnJtk r}z.ddj||f}|j|d|t|WYdd}~XnXdS)Nr-zUsing post-loaded profile '%s'z%Requested profile '%s' doesn't exist.FzCannot load profile(s) '%s': %s )splitr2rrrZprofile_locatorZget_known_names_notify_profile_changedrrloadr/r0r1rjoin)rrr4Z profile_listprofileerrstrr r!r!r"_load_profiles`s*    zDaemon._load_profilescCs2|jr"d}|j|d|t||j||dS)Nz/Cannot set profile while the daemon is running.F) is_runningr9rr>)rrr4r=r!r!r" set_profilezs zDaemon.set_profilecCs4|s d|_n$t|jdkr*d}t|n||_dS)NzYWhitespace is not allowed in profile names; only a single post-loaded profile is allowed.)r2lenr8r)r profile_namer=r!r!r"_set_post_loaded_profiles  zDaemon._set_post_loaded_profileFcCsV|jr"d}|j|d|t||j||j|||rR|j|||j|dS)Nz/Cannot set profile while the daemon is running.F)r?r9rrDr>_save_active_profile_save_post_loaded_profile)rZactive_profilesr4r5Zsave_instantlyr=r!r!r"r3s   zDaemon.set_all_profilescCs|jS)N)r/)rr!r!r"r<szDaemon.profilecCs|jS)N)r0)rr!r!r"r4sz Daemon.manualcCs|jr |jSdS)N)r/r2)rr!r!r"r5szDaemon.post_loaded_profilecCs|jS)N)r)rr!r!r"profile_recommenderszDaemon.profile_recommendercCs|jS)N)r)rr!r!r"rszDaemon.profile_loadercCs |jdk rtjtj||||S)N)rrZ send_signalr ZSIGNAL_PROFILE_CHANGED)rrresultr=r!r!r"r9s zDaemon._notify_profile_changedcCsj|jjddgdgd\}}|dkr&dS|dddkr:dS|jjddgdgd\}}tjd |dkoh| S) NZ systemctlzis-system-runningr)Z no_errorsFZstoppingz list-jobsz0\b(shutdown|reboot|halt|poweroff)\.target.*start)rZexecuteresearch)rZretcodeoutr!r!r"_full_rollback_requiredszDaemon._full_rollback_requiredcCs|jdkrtd|jj|jj|jdj|j|j|j |j |jj |j j tjd|jj|jrxtjdj|j}|j|dd|jj|jr|j}x\|jj|j|js|jr|d8}|dkr|j}tjd|jjtjd |jjqW|j jd}x.|jj|j |j rD|d krD|d7}qW|j!j"rZt#j$}njt#j%}|j&svtjd nN|j'd krt#j(}tjd t#j)t#j*fn$|jrtjdt#j$}n tjd|jr|jj+||jj,dS)Nz2Cannot start the daemon without setting a profile.r7z'static tuning from profile '%s' appliedTZOKrArzupdating monitorszperforming tuningsz1terminating TuneD due to system shutdown / rebootZ not_on_exitzMterminating TuneD and not rolling back any changes due to '%s' option in '%s'z+terminating TuneD, rolling back all changesz"terminating TuneD in one-shot mode)-r/rrZcreateZunitsrEr;r1r0rFr2Z start_tuningr+r*rrnamer rstartr9r)clearrrwaitr&r rr Zupdate_monitorsZ update_tuningr(r'is_setr Z ROLLBACK_FULLZ ROLLBACK_SOFTrMrZ ROLLBACK_NONErZGLOBAL_CONFIG_FILEZ stop_tuningZ destroy_all)rrZ _sleep_cntiZrollbackr!r!r" _thread_codesX          "        zDaemon._thread_codecCsHy|jj||Wn0tk rB}ztjt|WYdd}~XnXdS)N)rZsave_active_profilerrrstr)rrr4r r!r!r"rEszDaemon._save_active_profilecCsFy|jj|Wn0tk r@}ztjt|WYdd}~XnXdS)N)rZsave_post_loaded_profilerrrrV)rrCr r!r!r"rFsz Daemon._save_post_loaded_profilecCs&tjd|jj}tjd||S)NzWRunning in automatic mode, checking what profile is recommended for your configuration.zUsing '%s' profile)rrrZ recommend)rr<r!r!r"_get_recommended_profiles  zDaemon._get_recommended_profilecCs2|jj\}}|dkr|dk }|s*|j}||fS)N)rZget_active_profilerW)rr<r4r!r!r"r.s zDaemon._get_startup_profilecCs |jjjS)z$Return all accessible plugin classes)rplugins_repositoryZload_all_plugins)rr!r!r"get_all_plugins"szDaemon.get_all_pluginsc Cs.y|jjj|}Wntk r&dSX|jS)zReturn plugin class docstringr-)rrX load_plugin ImportError__doc__)r plugin_name plugin_classr!r!r"get_plugin_documentation&s  zDaemon.get_plugin_documentationc Cs0y|jjj|}Wntk r&iSX|jS)zReturn plugin's parameters and their hints Parameters: plugin_name -- plugins name Return: dictionary -- {parameter_name: hint} )rrXrZr[Zget_config_options_hints)rr]r^r!r!r"get_plugin_hints0s  zDaemon.get_plugin_hintscCs |jdk S)N)r/)rr!r!r" is_enabledAszDaemon.is_enabledcCs|jdk o|jjS)N)r$Zis_alive)rr!r!r"r?DszDaemon.is_runningcCs`|jr dS|jdkrdStjd|jjtj|jd|_ |j j |j j |j j dS)NFzstarting tuning)targetT)r?r/rrr(r*r%ZThreadrUr$r'rQr&rP)rr!r!r"rPGs      z Daemon.startcCs||jstjddS|jdkr.tjddS|jjsFtjddS|jjtjd|jj |j j |}|jj |S)NzTuneD is not runningFzno profile is setzprofile is not appliedzverifying profile(s): %s) r?rrr/r+rSr(rQrrOrZ verify_tuningr*)rZignore_missingretr!r!r"verify_profileVs        zDaemon.verify_profilecCsB|js dStjd|r$|jj|jj|jjd|_dS)NFzstopping tuningT)r?rrr'r*r&r$r;)rZprofile_switchr!r!r"stopls    z Daemon.stop)NNN)F)F) __name__ __module__ __qualname__r#rr,rr>r@rDr3propertyr<r4r5rGrr9rMrUrErFrWr.rYr_r`rar?rPrdrer!r!r!r"rs8 &         G r)oserrnor%Z tuned.logsZtunedZtuned.exceptionsrZtuned.profiles.exceptionsrZ tuned.constsr Ztuned.utils.commandsrrZtuned.utils.profile_recommenderrrJZlogsrrobjectrr!r!r!r"s       __pycache__/daemon.cpython-36.pyc000064400000025261147205076570012670 0ustar003 DaemonNcCstjdtj|_ttj|_ttj|_ tj |_ d|_ tj |_|dk r|jtjtj|_t|jtjtj|_t|jtjtj|_ |jtjtj |_ |jtjtj|_ |jtjtj |_||_|jdkrttj|_|j dkrd|_ n|j |jkr|j|_ |j |j|_tjd|j|j rJtjdtjd|j|j|jft|j d|_||_||_|jt |_!y|j"|Wn2t#k r}ztj$d |WYdd}~XnXdS) Nzinitializing daemonTrFz$using sleep interval of %d second(s)z8dynamic tuning is enabled (can be overridden by plugins)zFusing update interval of %d second(s) (%d times of the sleep interval))Z is_hardcodedz:Cannot set initial profile. No tunings will be enabled: %s)%logdebugconstsZCFG_DEF_DAEMON_daemonintZCFG_DEF_SLEEP_INTERVAL_sleep_intervalZCFG_DEF_UPDATE_INTERVALZ_update_intervalZCFG_DEF_DYNAMIC_TUNING_dynamic_tuningZ_recommend_commandZCFG_DEF_ROLLBACK _rollbackZget_boolZ CFG_DAEMONgetZCFG_SLEEP_INTERVALZCFG_UPDATE_INTERVALZCFG_DYNAMIC_TUNINGZCFG_RECOMMEND_COMMANDZCFG_DEF_RECOMMEND_COMMAND CFG_ROLLBACK _application _sleep_cyclesinfor_profile_recommender _unit_manager_profile_loader _init_threadsr_cmd _init_profilererror)selfZ unit_managerprofile_loader profile_namesconfigZ applicationer!/usr/lib/python3.6/daemon.py__init__sF        zDaemon.__init__cCsFd|_tj|_tj|_tj|_tj|_|jjtj|_dS)N) _thread threadingZEvent _terminate_terminate_profile_switch _not_used_sighup_processingset_profile_applied)rr!r!r"r7s     zDaemon._init_threadscCs|jddS)zARead configuration files again and load profile according to themN)r)rr!r!r"reload_profile_configCszDaemon.reload_profile_configcCsd}|jj}|dkrP|j\}}|dkrrd}|r<|d7}n|d7}tj|n"|dkrr|rhtjdn tjdd|_d|_g|_d|_|j |||dS)NTz.No profile is preset, running in manual mode. z(Only post-loaded profile will be enabledzNo profile will be enabled.) rZget_post_loaded_profile_get_startup_profilerr_profile_manual_active_profiles_post_loaded_profileset_all_profiles)rrmanualpost_loaded_profilemsgr!r!r"rGs&      zDaemon._init_profilecCs|pd}|j}|jr2tjd|j||jg}x:|D]2}||jjjkr8d|}|j|d|t|q8Wy.|r|j j ||_ nd|_ ||_ |j|_ WnJtk r}z.ddj||f}|j|d|t|WYdd}~XnXdS)Nr-zUsing post-loaded profile '%s'z%Requested profile '%s' doesn't exist.FzCannot load profile(s) '%s': %s )splitr2rrrZprofile_locatorZget_known_names_notify_profile_changedrrloadr/r0r1rjoin)rrr4Z profile_listprofileerrstrr r!r!r"_load_profiles`s*    zDaemon._load_profilescCs2|jr"d}|j|d|t||j||dS)Nz/Cannot set profile while the daemon is running.F) is_runningr9rr>)rrr4r=r!r!r" set_profilezs zDaemon.set_profilecCs4|s d|_n$t|jdkr*d}t|n||_dS)NzYWhitespace is not allowed in profile names; only a single post-loaded profile is allowed.)r2lenr8r)r profile_namer=r!r!r"_set_post_loaded_profiles  zDaemon._set_post_loaded_profileFcCsV|jr"d}|j|d|t||j||j|||rR|j|||j|dS)Nz/Cannot set profile while the daemon is running.F)r?r9rrDr>_save_active_profile_save_post_loaded_profile)rZactive_profilesr4r5Zsave_instantlyr=r!r!r"r3s   zDaemon.set_all_profilescCs|jS)N)r/)rr!r!r"r<szDaemon.profilecCs|jS)N)r0)rr!r!r"r4sz Daemon.manualcCs|jr |jSdS)N)r/r2)rr!r!r"r5szDaemon.post_loaded_profilecCs|jS)N)r)rr!r!r"profile_recommenderszDaemon.profile_recommendercCs|jS)N)r)rr!r!r"rszDaemon.profile_loadercCs |jdk rtjtj||||S)N)rrZ send_signalr ZSIGNAL_PROFILE_CHANGED)rrresultr=r!r!r"r9s zDaemon._notify_profile_changedcCsj|jjddgdgd\}}|dkr&dS|dddkr:dS|jjddgdgd\}}tjd |dkoh| S) NZ systemctlzis-system-runningr)Z no_errorsFZstoppingz list-jobsz0\b(shutdown|reboot|halt|poweroff)\.target.*start)rZexecuteresearch)rZretcodeoutr!r!r"_full_rollback_requiredszDaemon._full_rollback_requiredcCs|jdkrtd|jj|jj|jdj|j|j|j |j |jj |j j tjd|jj|jrxtjdj|j}|j|dd|jj|jr|j}x\|jj|j|js|jr|d8}|dkr|j}tjd|jjtjd |jjqW|j jd}x.|jj|j |j rD|d krD|d7}qW|j!j"rZt#j$}njt#j%}|j&svtjd nN|j'd krt#j(}tjd t#j)t#j*fn$|jrtjdt#j$}n tjd|jr|jj+||jj,dS)Nz2Cannot start the daemon without setting a profile.r7z'static tuning from profile '%s' appliedTZOKrArzupdating monitorszperforming tuningsz1terminating TuneD due to system shutdown / rebootZ not_on_exitzMterminating TuneD and not rolling back any changes due to '%s' option in '%s'z+terminating TuneD, rolling back all changesz"terminating TuneD in one-shot mode)-r/rrZcreateZunitsrEr;r1r0rFr2Z start_tuningr+r*rrnamer rstartr9r)clearrrwaitr&r rr Zupdate_monitorsZ update_tuningr(r'is_setr Z ROLLBACK_FULLZ ROLLBACK_SOFTrMrZ ROLLBACK_NONErZGLOBAL_CONFIG_FILEZ stop_tuningZ destroy_all)rrZ _sleep_cntiZrollbackr!r!r" _thread_codesX          "        zDaemon._thread_codecCsHy|jj||Wn0tk rB}ztjt|WYdd}~XnXdS)N)rZsave_active_profilerrrstr)rrr4r r!r!r"rEszDaemon._save_active_profilecCsFy|jj|Wn0tk r@}ztjt|WYdd}~XnXdS)N)rZsave_post_loaded_profilerrrrV)rrCr r!r!r"rFsz Daemon._save_post_loaded_profilecCs&tjd|jj}tjd||S)NzWRunning in automatic mode, checking what profile is recommended for your configuration.zUsing '%s' profile)rrrZ recommend)rr<r!r!r"_get_recommended_profiles  zDaemon._get_recommended_profilecCs2|jj\}}|dkr|dk }|s*|j}||fS)N)rZget_active_profilerW)rr<r4r!r!r"r.s zDaemon._get_startup_profilecCs |jjjS)z$Return all accessible plugin classes)rplugins_repositoryZload_all_plugins)rr!r!r"get_all_plugins"szDaemon.get_all_pluginsc Cs.y|jjj|}Wntk r&dSX|jS)zReturn plugin class docstringr-)rrX load_plugin ImportError__doc__)r plugin_name plugin_classr!r!r"get_plugin_documentation&s  zDaemon.get_plugin_documentationc Cs0y|jjj|}Wntk r&iSX|jS)zReturn plugin's parameters and their hints Parameters: plugin_name -- plugins name Return: dictionary -- {parameter_name: hint} )rrXrZr[Zget_config_options_hints)rr]r^r!r!r"get_plugin_hints0s  zDaemon.get_plugin_hintscCs |jdk S)N)r/)rr!r!r" is_enabledAszDaemon.is_enabledcCs|jdk o|jjS)N)r$Zis_alive)rr!r!r"r?DszDaemon.is_runningcCs`|jr dS|jdkrdStjd|jjtj|jd|_ |j j |j j |j j dS)NFzstarting tuning)targetT)r?r/rrr(r*r%ZThreadrUr$r'rQr&rP)rr!r!r"rPGs      z Daemon.startcCs||jstjddS|jdkr.tjddS|jjsFtjddS|jjtjd|jj |j j |}|jj |S)NzTuneD is not runningFzno profile is setzprofile is not appliedzverifying profile(s): %s) r?rrr/r+rSr(rQrrOrZ verify_tuningr*)rZignore_missingretr!r!r"verify_profileVs        zDaemon.verify_profilecCsB|js dStjd|r$|jj|jj|jjd|_dS)NFzstopping tuningT)r?rrr'r*r&r$r;)rZprofile_switchr!r!r"stopls    z Daemon.stop)NNN)F)F) __name__ __module__ __qualname__r#rr,rr>r@rDr3propertyr<r4r5rGrr9rMrUrErFrWr.rYr_r`rar?rPrdrer!r!r!r"rs8 &         G r)oserrnor%Z tuned.logsZtunedZtuned.exceptionsrZtuned.profiles.exceptionsrZ tuned.constsr Ztuned.utils.commandsrrZtuned.utils.profile_recommenderrrJZlogsrrobjectrr!r!r!r"s       __init__.py000064400000000113147205076570006665 0ustar00from .application import * from .controller import * from .daemon import * application.py000064400000017227147205076570007447 0ustar00from tuned import storage, units, monitors, plugins, profiles, exports, hardware from tuned.exceptions import TunedException import tuned.logs import tuned.version from . import controller from . import daemon import signal import os import sys import select import struct import tuned.consts as consts from tuned.utils.global_config import GlobalConfig log = tuned.logs.get() __all__ = ["Application"] class Application(object): def __init__(self, profile_name = None, config = None): # os.uname()[2] is for the python-2.7 compatibility, it's the release string # like e.g. '5.15.13-100.fc34.x86_64' log.info("TuneD: %s, kernel: %s" % (tuned.version.TUNED_VERSION_STR, os.uname()[2])) self._dbus_exporter = None self._unix_socket_exporter = None storage_provider = storage.PickleProvider() storage_factory = storage.Factory(storage_provider) self.config = GlobalConfig() if config is None else config if self.config.get_bool(consts.CFG_DYNAMIC_TUNING): log.info("dynamic tuning is enabled (can be overridden in plugins)") else: log.info("dynamic tuning is globally disabled") monitors_repository = monitors.Repository() udev_buffer_size = self.config.get_size("udev_buffer_size", consts.CFG_DEF_UDEV_BUFFER_SIZE) hardware_inventory = hardware.Inventory(buffer_size=udev_buffer_size) device_matcher = hardware.DeviceMatcher() device_matcher_udev = hardware.DeviceMatcherUdev() plugin_instance_factory = plugins.instance.Factory() self.variables = profiles.variables.Variables() plugins_repository = plugins.Repository(monitors_repository, storage_factory, hardware_inventory,\ device_matcher, device_matcher_udev, plugin_instance_factory, self.config, self.variables) def_instance_priority = int(self.config.get(consts.CFG_DEFAULT_INSTANCE_PRIORITY, consts.CFG_DEF_DEFAULT_INSTANCE_PRIORITY)) unit_manager = units.Manager( plugins_repository, monitors_repository, def_instance_priority, hardware_inventory, self.config) profile_factory = profiles.Factory() profile_merger = profiles.Merger() profile_locator = profiles.Locator(consts.LOAD_DIRECTORIES) profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config, self.variables) self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self) self._controller = controller.Controller(self._daemon, self.config) self._init_signals() self._pid_file = None def _handle_signal(self, signal_number, handler): def handler_wrapper(_signal_number, _frame): if signal_number == _signal_number: handler() signal.signal(signal_number, handler_wrapper) def _init_signals(self): self._handle_signal(signal.SIGHUP, self._controller.sighup) self._handle_signal(signal.SIGINT, self._controller.terminate) self._handle_signal(signal.SIGTERM, self._controller.terminate) def attach_to_dbus(self, bus_name, object_name, interface_name, namespace): if self._dbus_exporter is not None: raise TunedException("DBus interface is already initialized.") self._dbus_exporter = exports.dbus.DBusExporter(bus_name, interface_name, object_name, namespace) exports.register_exporter(self._dbus_exporter) def attach_to_unix_socket(self): if self._unix_socket_exporter is not None: raise TunedException("Unix socket interface is already initialized.") self._unix_socket_exporter = exports.unix_socket.UnixSocketExporter(self.config.get(consts.CFG_UNIX_SOCKET_PATH), self.config.get(consts.CFG_UNIX_SOCKET_SIGNAL_PATHS), self.config.get(consts.CFG_UNIX_SOCKET_OWNERSHIP), self.config.get_int(consts.CFG_UNIX_SOCKET_PERMISIONS), self.config.get_int(consts.CFG_UNIX_SOCKET_CONNECTIONS_BACKLOG)) exports.register_exporter(self._unix_socket_exporter) def register_controller(self): exports.register_object(self._controller) def _daemonize_parent(self, parent_in_fd, child_out_fd): """ Wait till the child signalizes that the initialization is complete by writing some uninteresting data into the pipe. """ os.close(child_out_fd) (read_ready, drop, drop) = select.select([parent_in_fd], [], [], consts.DAEMONIZE_PARENT_TIMEOUT) if len(read_ready) != 1: os.close(parent_in_fd) raise TunedException("Cannot daemonize, timeout when waiting for the child process.") response = os.read(parent_in_fd, 8) os.close(parent_in_fd) if len(response) == 0: raise TunedException("Cannot daemonize, no response from child process received.") try: val = struct.unpack("?", response)[0] except struct.error: raise TunedException("Cannot daemonize, invalid response from child process received.") if val != True: raise TunedException("Cannot daemonize, child process reports failure.") def write_pid_file(self, pid_file = consts.PID_FILE): self._pid_file = pid_file self._delete_pid_file() try: dir_name = os.path.dirname(self._pid_file) if not os.path.exists(dir_name): os.makedirs(dir_name) with os.fdopen(os.open(self._pid_file, os.O_CREAT|os.O_TRUNC|os.O_WRONLY , 0o644), "w") as f: f.write("%d" % os.getpid()) except (OSError,IOError) as error: log.critical("cannot write the PID to %s: %s" % (self._pid_file, str(error))) def _delete_pid_file(self): if os.path.exists(self._pid_file): try: os.unlink(self._pid_file) except OSError as error: log.warning("cannot remove existing PID file %s, %s" % (self._pid_file, str(error))) def _daemonize_child(self, pid_file, parent_in_fd, child_out_fd): """ Finishes daemonizing process, writes a PID file and signalizes to the parent that the initialization is complete. """ os.close(parent_in_fd) os.chdir("/") os.setsid() os.umask(0) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as error: log.critical("cannot daemonize, fork() error: %s" % str(error)) val = struct.pack("?", False) os.write(child_out_fd, val) os.close(child_out_fd) raise TunedException("Cannot daemonize, second fork() failed.") fd = open("/dev/null", "w+") os.dup2(fd.fileno(), sys.stdin.fileno()) os.dup2(fd.fileno(), sys.stdout.fileno()) os.dup2(fd.fileno(), sys.stderr.fileno()) self.write_pid_file(pid_file) log.debug("successfully daemonized") val = struct.pack("?", True) os.write(child_out_fd, val) os.close(child_out_fd) def daemonize(self, pid_file = consts.PID_FILE): """ Daemonizes the application. In case of failure, TunedException is raised in the parent process. If the operation is successfull, the main process is terminated and only child process returns from this method. """ parent_child_fds = os.pipe() try: child_pid = os.fork() except OSError as error: os.close(parent_child_fds[0]) os.close(parent_child_fds[1]) raise TunedException("Cannot daemonize, fork() failed.") try: if child_pid > 0: self._daemonize_parent(*parent_child_fds) sys.exit(0) else: self._daemonize_child(pid_file, *parent_child_fds) except: # pass exceptions only into parent process if child_pid > 0: raise else: sys.exit(1) @property def daemon(self): return self._daemon @property def controller(self): return self._controller def run(self, daemon): # override global config if ran from command line with daemon option (-d) if daemon: self.config.set(consts.CFG_DAEMON, True) if not self.config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON): log.warn("Using one shot no daemon mode, most of the functionality will be not available, it can be changed in global config") result = self._controller.run() if self.config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON): exports.stop() if self._pid_file is not None: self._delete_pid_file() return result controller.py000064400000031165147205076570007324 0ustar00from tuned import exports import tuned.logs import tuned.exceptions from tuned.exceptions import TunedException import threading import tuned.consts as consts from tuned.utils.commands import commands __all__ = ["Controller"] log = tuned.logs.get() class TimerStore(object): def __init__(self): self._timers = dict() self._timers_lock = threading.Lock() def store_timer(self, token, timer): with self._timers_lock: self._timers[token] = timer def drop_timer(self, token): with self._timers_lock: try: timer = self._timers[token] timer.cancel() del self._timers[token] except: pass def cancel_all(self): with self._timers_lock: for timer in self._timers.values(): timer.cancel() self._timers.clear() class Controller(tuned.exports.interfaces.ExportableInterface): """ Controller's purpose is to keep the program running, start/stop the tuning, and export the controller interface (currently only over D-Bus). """ def __init__(self, daemon, global_config): super(Controller, self).__init__() self._daemon = daemon self._global_config = global_config self._terminate = threading.Event() self._cmd = commands() self._timer_store = TimerStore() def run(self): """ Controller main loop. The call is blocking. """ log.info("starting controller") res = self.start() daemon = self._global_config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) if not res and daemon: exports.start() if daemon: self._terminate.clear() # we have to pass some timeout, otherwise signals will not work while not self._cmd.wait(self._terminate, 1): exports.period_check() log.info("terminating controller") self.stop() def terminate(self): self._terminate.set() def sighup(self): if not self._daemon._sighup_processing.is_set(): self._daemon._sighup_processing.set() if not self.reload(): self._daemon._sighup_processing.clear() @exports.signal("sbs") def profile_changed(self, profile_name, result, errstr): pass # exports decorator checks the authorization (currently through polkit), caller is None if # no authorization was performed (i.e. the call should process as authorized), string # identifying caller (with DBus it's the caller bus name) if authorized and empty # string if not authorized, caller must be the last argument def _log_capture_abort(self, token): tuned.logs.log_capture_finish(token) self._timer_store.drop_timer(token) @exports.export("ii", "s") def log_capture_start(self, log_level, timeout, caller = None): if caller == "": return "" token = tuned.logs.log_capture_start(log_level) if token is None: return "" if timeout > 0: timer = threading.Timer(timeout, self._log_capture_abort, args = [token]) self._timer_store.store_timer(token, timer) timer.start() return "" if token is None else token @exports.export("s", "s") def log_capture_finish(self, token, caller = None): if caller == "": return "" res = tuned.logs.log_capture_finish(token) self._timer_store.drop_timer(token) return "" if res is None else res @exports.export("", "b") def start(self, caller = None): if caller == "": return False if self._global_config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON): if self._daemon.is_running(): return True elif not self._daemon.is_enabled(): return False return self._daemon.start() def _stop(self, profile_switch = False): if not self._daemon.is_running(): res = True else: res = self._daemon.stop(profile_switch = profile_switch) self._timer_store.cancel_all() return res @exports.export("", "b") def stop(self, caller = None): if caller == "": return False return self._stop(profile_switch = False) @exports.export("", "b") def reload(self, caller = None): if caller == "": return False if self._daemon.is_running(): stop_ok = self._stop(profile_switch = True) if not stop_ok: return False try: self._daemon.reload_profile_config() except TunedException as e: log.error("Failed to reload TuneD: %s" % e) return False return self.start() def _switch_profile(self, profile_name, manual): was_running = self._daemon.is_running() msg = "OK" success = True reapply = False try: if was_running: self._daemon.stop(profile_switch = True) self._daemon.set_profile(profile_name, manual) except tuned.exceptions.TunedException as e: success = False msg = str(e) if was_running and self._daemon.profile.name == profile_name: log.error("Failed to reapply profile '%s'. Did it change on disk and break?" % profile_name) reapply = True else: log.error("Failed to apply profile '%s'" % profile_name) finally: if was_running: if reapply: log.warn("Applying previously applied (possibly out-dated) profile '%s'." % profile_name) elif not success: log.info("Applying previously applied profile.") self._daemon.start() return (success, msg) @exports.export("s", "(bs)") def switch_profile(self, profile_name, caller = None): if caller == "": return (False, "Unauthorized") return self._switch_profile(profile_name, True) @exports.export("", "(bs)") def auto_profile(self, caller = None): if caller == "": return (False, "Unauthorized") profile_name = self.recommend_profile() return self._switch_profile(profile_name, False) @exports.export("", "s") def active_profile(self, caller = None): if caller == "": return "" if self._daemon.profile is not None: return self._daemon.profile.name else: return "" @exports.export("", "(ss)") def profile_mode(self, caller = None): if caller == "": return "unknown", "Unauthorized" manual = self._daemon.manual if manual is None: # This means no profile is applied. Check the preset value. try: profile, manual = self._cmd.get_active_profile() if manual is None: manual = profile is not None except TunedException as e: mode = "unknown" error = str(e) return mode, error mode = consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO return mode, "" @exports.export("", "s") def post_loaded_profile(self, caller = None): if caller == "": return "" return self._daemon.post_loaded_profile or "" @exports.export("", "b") def disable(self, caller = None): if caller == "": return False if self._daemon.is_running(): self._daemon.stop() if self._daemon.is_enabled(): self._daemon.set_all_profiles(None, True, None, save_instantly=True) return True @exports.export("", "b") def is_running(self, caller = None): if caller == "": return False return self._daemon.is_running() @exports.export("", "as") def profiles(self, caller = None): if caller == "": return [] return self._daemon.profile_loader.profile_locator.get_known_names() @exports.export("", "a(ss)") def profiles2(self, caller = None): if caller == "": return [] return self._daemon.profile_loader.profile_locator.get_known_names_summary() @exports.export("s", "(bsss)") def profile_info(self, profile_name, caller = None): if caller == "": return tuple(False, "", "", "") if profile_name is None or profile_name == "": profile_name = self.active_profile() return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""])) @exports.export("", "s") def recommend_profile(self, caller = None): if caller == "": return "" return self._daemon.profile_recommender.recommend() @exports.export("", "b") def verify_profile(self, caller = None): if caller == "": return False return self._daemon.verify_profile(ignore_missing = False) @exports.export("", "b") def verify_profile_ignore_missing(self, caller = None): if caller == "": return False return self._daemon.verify_profile(ignore_missing = True) @exports.export("", "a{sa{ss}}") def get_all_plugins(self, caller = None): """Return dictionary with accesible plugins Return: dictionary -- {plugin_name: {parameter_name: default_value}} """ if caller == "": return False plugins = {} for plugin_class in self._daemon.get_all_plugins(): plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1] conf_options = plugin_class._get_config_options() plugins[plugin_name] = {} for key, val in conf_options.items(): plugins[plugin_name][key] = str(val) return plugins @exports.export("s","s") def get_plugin_documentation(self, plugin_name, caller = None): """Return docstring of plugin's class""" if caller == "": return False return self._daemon.get_plugin_documentation(str(plugin_name)) @exports.export("s","a{ss}") def get_plugin_hints(self, plugin_name, caller = None): """Return dictionary with plugin's parameters and their hints Parameters: plugin_name -- name of plugin Return: dictionary -- {parameter_name: hint} """ if caller == "": return False return self._daemon.get_plugin_hints(str(plugin_name)) @exports.export("s", "b") def register_socket_signal_path(self, path, caller = None): """Allows to dynamically add sockets to send signals to Parameters: path -- path to socket to register for sending signals Return: bool -- True on success """ if caller == "": return False if self._daemon._application and self._daemon._application._unix_socket_exporter: self._daemon._application._unix_socket_exporter.register_signal_path(path) return True return False # devices - devices to migrate from other instances, string of form "dev1,dev2,dev3,..." # or "cpulist:CPULIST", where CPULIST is e.g. "0-3,6,8-9" # instance_name - instance where to migrate devices @exports.export("ss", "(bs)") def instance_acquire_devices(self, devices, instance_name, caller = None): if caller == "": return (False, "Unauthorized") found = False for instance_target in self._daemon._unit_manager.instances: if instance_target.name == instance_name: log.debug("Found instance '%s'." % instance_target.name) found = True break if not found: rets = "Instance '%s' not found" % instance_name log.error(rets) return (False, rets) devs = set(self._cmd.devstr2devs(devices)) log.debug("Instance '%s' trying to acquire devices '%s'." % (instance_target.name, str(devs))) for instance in self._daemon._unit_manager.instances: devs_moving = instance.processed_devices & devs if len(devs_moving): devs -= devs_moving log.info("Moving devices '%s' from instance '%s' to instance '%s'." % (str(devs_moving), instance.name, instance_target.name)) if (instance.plugin.name != instance_target.plugin.name): rets = "Target instance '%s' is of type '%s', but devices '%s' are currently handled by " \ "instance '%s' which is of type '%s'." % (instance_target.name, instance_target.plugin.name, str(devs_moving), instance.name, instance.plugin.name) log.error(rets) return (False, rets) instance.plugin._remove_devices_nocheck(instance, devs_moving) instance_target.plugin._add_devices_nocheck(instance_target, devs_moving) if (len(devs)): rets = "Ignoring devices not handled by any instance '%s'." % str(devs) log.info(rets) return (False, rets) return (True, "OK") @exports.export("s", "(bsa(ss))") def get_instances(self, plugin_name, caller = None): """Return a list of active instances of a plugin or all active instances Parameters: plugin_name -- name of the plugin or an empty string Return: bool -- True on success string -- error message or "OK" list of string pairs -- [(instance_name, plugin_name)] """ if caller == "": return (False, "Unauthorized", []) if plugin_name != "" and plugin_name not in self.get_all_plugins().keys(): rets = "Plugin '%s' does not exist" % plugin_name log.error(rets) return (False, rets, []) instances = filter(lambda instance: instance.active, self._daemon._unit_manager.instances) if plugin_name != "": instances = filter(lambda instance: instance.plugin.name == plugin_name, instances) return (True, "OK", list(map(lambda instance: (instance.name, instance.plugin.name), instances))) @exports.export("s", "(bsas)") def instance_get_devices(self, instance_name, caller = None): """Return a list of devices assigned to an instance Parameters: instance_name -- name of the instance Return: bool -- True on success string -- error message or "OK" list of strings -- device names """ if caller == "": return (False, "Unauthorized", []) for instance in self._daemon._unit_manager.instances: if instance.name == instance_name: return (True, "OK", sorted(list(instance.processed_devices))) rets = "Instance '%s' not found" % instance_name log.error(rets) return (False, rets, []) daemon.py000064400000031671147205076570006406 0ustar00import os import errno import threading import tuned.logs from tuned.exceptions import TunedException from tuned.profiles.exceptions import InvalidProfileException import tuned.consts as consts from tuned.utils.commands import commands from tuned import exports from tuned.utils.profile_recommender import ProfileRecommender import re log = tuned.logs.get() class Daemon(object): def __init__(self, unit_manager, profile_loader, profile_names=None, config=None, application=None): log.debug("initializing daemon") self._daemon = consts.CFG_DEF_DAEMON self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) self._update_interval = int(consts.CFG_DEF_UPDATE_INTERVAL) self._dynamic_tuning = consts.CFG_DEF_DYNAMIC_TUNING self._recommend_command = True self._rollback = consts.CFG_DEF_ROLLBACK if config is not None: self._daemon = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) self._sleep_interval = int(config.get(consts.CFG_SLEEP_INTERVAL, consts.CFG_DEF_SLEEP_INTERVAL)) self._update_interval = int(config.get(consts.CFG_UPDATE_INTERVAL, consts.CFG_DEF_UPDATE_INTERVAL)) self._dynamic_tuning = config.get_bool(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING) self._recommend_command = config.get_bool(consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND) self._rollback = config.get(consts.CFG_ROLLBACK, consts.CFG_DEF_ROLLBACK) self._application = application if self._sleep_interval <= 0: self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) if self._update_interval == 0: self._dynamic_tuning = False elif self._update_interval < self._sleep_interval: self._update_interval = self._sleep_interval self._sleep_cycles = self._update_interval // self._sleep_interval log.info("using sleep interval of %d second(s)" % self._sleep_interval) if self._dynamic_tuning: log.info("dynamic tuning is enabled (can be overridden by plugins)") log.info("using update interval of %d second(s) (%d times of the sleep interval)" % (self._sleep_cycles * self._sleep_interval, self._sleep_cycles)) self._profile_recommender = ProfileRecommender(is_hardcoded = not self._recommend_command) self._unit_manager = unit_manager self._profile_loader = profile_loader self._init_threads() self._cmd = commands() try: self._init_profile(profile_names) except TunedException as e: log.error("Cannot set initial profile. No tunings will be enabled: %s" % e) def _init_threads(self): self._thread = None self._terminate = threading.Event() # Flag which is set if terminating due to profile_switch self._terminate_profile_switch = threading.Event() # Flag which is set if there is no operation in progress self._not_used = threading.Event() # Flag which is set if SIGHUP is being processed self._sighup_processing = threading.Event() self._not_used.set() self._profile_applied = threading.Event() def reload_profile_config(self): """Read configuration files again and load profile according to them""" self._init_profile(None) def _init_profile(self, profile_names): manual = True post_loaded_profile = self._cmd.get_post_loaded_profile() if profile_names is None: (profile_names, manual) = self._get_startup_profile() if profile_names is None: msg = "No profile is preset, running in manual mode. " if post_loaded_profile: msg += "Only post-loaded profile will be enabled" else: msg += "No profile will be enabled." log.info(msg) # Passed through '-p' cmdline option elif profile_names == "": if post_loaded_profile: log.info("Only post-loaded profile will be enabled") else: log.info("No profile will be enabled.") self._profile = None self._manual = None self._active_profiles = [] self._post_loaded_profile = None self.set_all_profiles(profile_names, manual, post_loaded_profile) def _load_profiles(self, profile_names, manual): profile_names = profile_names or "" profile_list = profile_names.split() if self._post_loaded_profile: log.info("Using post-loaded profile '%s'" % self._post_loaded_profile) profile_list = profile_list + [self._post_loaded_profile] for profile in profile_list: if profile not in self.profile_loader.profile_locator.get_known_names(): errstr = "Requested profile '%s' doesn't exist." % profile self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) try: if profile_list: self._profile = self._profile_loader.load(profile_list) else: self._profile = None self._manual = manual self._active_profiles = profile_names.split() except InvalidProfileException as e: errstr = "Cannot load profile(s) '%s': %s" % (" ".join(profile_list), e) self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) def set_profile(self, profile_names, manual): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) self._load_profiles(profile_names, manual) def _set_post_loaded_profile(self, profile_name): if not profile_name: self._post_loaded_profile = None elif len(profile_name.split()) > 1: errstr = "Whitespace is not allowed in profile names; only a single post-loaded profile is allowed." raise TunedException(errstr) else: self._post_loaded_profile = profile_name def set_all_profiles(self, active_profiles, manual, post_loaded_profile, save_instantly=False): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(active_profiles, False, errstr) raise TunedException(errstr) self._set_post_loaded_profile(post_loaded_profile) self._load_profiles(active_profiles, manual) if save_instantly: self._save_active_profile(active_profiles, manual) self._save_post_loaded_profile(post_loaded_profile) @property def profile(self): return self._profile @property def manual(self): return self._manual @property def post_loaded_profile(self): # Return the profile name only if the profile is active. If # the profile is not active, then the value is meaningless. return self._post_loaded_profile if self._profile else None @property def profile_recommender(self): return self._profile_recommender @property def profile_loader(self): return self._profile_loader # send notification when profile is changed (everything is setup) or if error occured # result: True - OK, False - error occured def _notify_profile_changed(self, profile_names, result, errstr): if self._application is not None: exports.send_signal(consts.SIGNAL_PROFILE_CHANGED, profile_names, result, errstr) return errstr def _full_rollback_required(self): retcode, out = self._cmd.execute(["systemctl", "is-system-running"], no_errors = [0]) if retcode < 0: return False if out[:8] == "stopping": return False retcode, out = self._cmd.execute(["systemctl", "list-jobs"], no_errors = [0]) return re.search(r"\b(shutdown|reboot|halt|poweroff)\.target.*start", out) is None and not retcode def _thread_code(self): if self._profile is None: raise TunedException("Cannot start the daemon without setting a profile.") self._unit_manager.create(self._profile.units) self._save_active_profile(" ".join(self._active_profiles), self._manual) self._save_post_loaded_profile(self._post_loaded_profile) self._unit_manager.start_tuning() self._profile_applied.set() log.info("static tuning from profile '%s' applied" % self._profile.name) if self._daemon: exports.start() profile_names = " ".join(self._active_profiles) self._notify_profile_changed(profile_names, True, "OK") self._sighup_processing.clear() if self._daemon: # In python 2 interpreter with applied patch for rhbz#917709 we need to periodically # poll, otherwise the python will not have chance to update events / locks (due to GIL) # and e.g. DBus control will not work. The polling interval of 1 seconds (which is # the default) is still much better than 50 ms polling with unpatched interpreter. # For more details see TuneD rhbz#917587. _sleep_cnt = self._sleep_cycles while not self._cmd.wait(self._terminate, self._sleep_interval): if self._dynamic_tuning: _sleep_cnt -= 1 if _sleep_cnt <= 0: _sleep_cnt = self._sleep_cycles log.debug("updating monitors") self._unit_manager.update_monitors() log.debug("performing tunings") self._unit_manager.update_tuning() self._profile_applied.clear() # wait for others to complete their tasks, use timeout 3 x sleep_interval to prevent # deadlocks i = 0 while not self._cmd.wait(self._not_used, self._sleep_interval) and i < 3: i += 1 # if terminating due to profile switch if self._terminate_profile_switch.is_set(): rollback = consts.ROLLBACK_FULL else: # Assume only soft rollback is needed. Soft rollback means reverting all # non-persistent tunings applied by a plugin instance. In contrast to full # rollback, information about what to revert is kept in RAM (volatile # memory) -- TuneD data structures. # With systemd TuneD detects system shutdown and in such a case it doesn't # perform full cleanup. If the system is not shutting down, it means that TuneD # was explicitly stopped by the user and in such case do the full cleanup. On # systems without systemd, full cleanup is never performed. rollback = consts.ROLLBACK_SOFT if not self._full_rollback_required(): log.info("terminating TuneD due to system shutdown / reboot") elif self._rollback == "not_on_exit": # no rollback on TuneD exit whatsoever rollback = consts.ROLLBACK_NONE log.info("terminating TuneD and not rolling back any changes due to '%s' option in '%s'" % (consts.CFG_ROLLBACK, consts.GLOBAL_CONFIG_FILE)) else: if self._daemon: log.info("terminating TuneD, rolling back all changes") rollback = consts.ROLLBACK_FULL else: log.info("terminating TuneD in one-shot mode") if self._daemon: self._unit_manager.stop_tuning(rollback) self._unit_manager.destroy_all() def _save_active_profile(self, profile_names, manual): try: self._cmd.save_active_profile(profile_names, manual) except TunedException as e: log.error(str(e)) def _save_post_loaded_profile(self, profile_name): try: self._cmd.save_post_loaded_profile(profile_name) except TunedException as e: log.error(str(e)) def _get_recommended_profile(self): log.info("Running in automatic mode, checking what profile is recommended for your configuration.") profile = self._profile_recommender.recommend() log.info("Using '%s' profile" % profile) return profile def _get_startup_profile(self): profile, manual = self._cmd.get_active_profile() if manual is None: manual = profile is not None if not manual: profile = self._get_recommended_profile() return profile, manual def get_all_plugins(self): """Return all accessible plugin classes""" return self._unit_manager.plugins_repository.load_all_plugins() def get_plugin_documentation(self, plugin_name): """Return plugin class docstring""" try: plugin_class = self._unit_manager.plugins_repository.load_plugin( plugin_name ) except ImportError: return "" return plugin_class.__doc__ def get_plugin_hints(self, plugin_name): """Return plugin's parameters and their hints Parameters: plugin_name -- plugins name Return: dictionary -- {parameter_name: hint} """ try: plugin_class = self._unit_manager.plugins_repository.load_plugin( plugin_name ) except ImportError: return {} return plugin_class.get_config_options_hints() def is_enabled(self): return self._profile is not None def is_running(self): return self._thread is not None and self._thread.is_alive() def start(self): if self.is_running(): return False if self._profile is None: return False log.info("starting tuning") self._not_used.set() self._thread = threading.Thread(target=self._thread_code) self._terminate_profile_switch.clear() self._terminate.clear() self._thread.start() return True def verify_profile(self, ignore_missing): if not self.is_running(): log.error("TuneD is not running") return False if self._profile is None: log.error("no profile is set") return False if not self._profile_applied.is_set(): log.error("profile is not applied") return False # using daemon, the main loop mustn't exit before our completion self._not_used.clear() log.info("verifying profile(s): %s" % self._profile.name) ret = self._unit_manager.verify_tuning(ignore_missing) # main loop is allowed to exit self._not_used.set() return ret # profile_switch is helper telling plugins whether the stop is due to profile switch def stop(self, profile_switch = False): if not self.is_running(): return False log.info("stopping tuning") if profile_switch: self._terminate_profile_switch.set() self._terminate.set() self._thread.join() self._thread = None return True