
    epjs#                    ,   U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ  ej        e          ZdZdZd	Z ej                    Zd	ad
adaded<   dad.dZd/dZd0dZd1dZ d2dZ!d3d4dZ"d5d%Z#d6d&Z$d
d'dd(d7d-Z%dS )8a  Rate-limited heap release for long-lived Hermes gateway processes.

On Linux/glibc, ``malloc_trim(0)`` can return pages from freed Python/C
allocations to the OS.  Other platforms and allocators are safe no-ops.
Behavior is configured under ``context.memory_trim`` in ``config.yaml``.
    )annotationsN)Callable)Path)Anyg      N@           FCallable[[int], int] | None_malloc_trimreturntuple[bool, float, int, float]c                    d} t           }t          }t          }	 ddlm}  |            pi }t          |t                    r|                    d          nd}t          |t                    r|                    d          nd}t          |t                    r}|                    d          }t          |t                    r|} |                    dt                     }|                    d	t                    }|                    d
t                    }n# t          $ r Y nw xY w| t          |          t          |          t          |t                    fS )z=Return fail-open settings from the normal Hermes config path.Tr   )load_config_readonlycontextNmemory_trimenabledcooldown_secondslog_every_ninfo_log_min_delta_mb)_DEFAULT_COOLDOWN_SECONDS_DEFAULT_LOG_EVERY_N_DEFAULT_INFO_LOG_MIN_DELTA_MBhermes_cli.configr   
isinstancedictgetbool	Exception_cooldown_seconds_log_every_n_nonnegative_float)	r   cooldownr   r   r   configr   settingsconfigured_enableds	            9/home/thesage/.hermes/hermes-agent/hermes_cli/mem_trim.py_config_settingsr&   !   sd   G-H+K!? 	;:::::%%''-2+5fd+C+CM&**Y'''1;GT1J1JT7;;}---PTh%% 	!)i!8!8,d33 -,||$68QRRH",,}6JKKK$,LL')G% %!     	(##[!!02PQQ	 s   C<D 
D#"D#valuer   floatc                    t          | t                    rt          S 	 t          dt	          |                     S # t
          t          f$ r
 t          cY S w xY wNr   )r   r   r   maxr(   	TypeError
ValueErrorr'   s    r%   r   r   E   sa    % )(()3e%%%z" ) ) )(((()   ; AAintc                    t          | t                    rt          S 	 t          dt	          |                     S # t
          t          f$ r
 t          cY S w xY w)Nr   )r   r   r   r+   r0   r,   r-   r.   s    r%   r   r   N   sa    % $##$1c%jj!!!z" $ $ $####$r/   defaultc                    t          | t                    r|S 	 t          dt          |                     S # t          t
          f$ r |cY S w xY wr*   )r   r   r+   r(   r,   r-   )r'   r2   s     r%   r    r    W   s]    % 3e%%%z"   s   6 AA
str | Nonec                     t           j        dk    rdS 	 t          d                              d          S # t          $ r Y dS w xY w)zHRead Linux process status without making non-Linux callers special-case.linuxNz/proc/self/statuszutf-8)encoding)sysplatformr   	read_textOSError     r%   _read_proc_statusr>   `   s[    
|wt'((22G2DDD   tts   "7 
AAhistory_bytes
int | Nonedict[str, int | None]c                   ddt          j                    d}t                      }|r|                                D ]}|                    d          \  }}}|r|dvr"|                                                    d          }|r:|d                                         r t          |d                   ||dk    rd	nd
<   t          | t                    r| dk    r| |d<   |S )zReturn lightweight process-memory telemetry for trim logs and canaries.

    ``VmRSS`` and ``RssAnon`` are Linux-only best effort fields.  The helper is
    intentionally dependency-free so allocation recovery never requires psutil.
    N)rss_kibrss_anon_kibthread_count:>   VmRSSRssAnonr   )maxsplitr   rG   rC   rD   r?   )
	threadingactive_countr>   
splitlines	partitionstripsplitisdigitr0   r   )r?   snapshotstatuslinekey	separator	raw_valuer'   s           r%   collect_memory_snapshotrW   j   s    !.00' 'H
   F Z%%'' 	Z 	ZD(,s(;(;%CI +? ? ?OO%%++Q+77E Zq))++ ZLOPUVWPXMMcWnn.I-%% 2-1*<*<$1!Or=   forcer   r   
call_countbeforeafterr   c                    | rdS | s||z  rdS |                     d          }|                     d          }||dS t          ||z
            |dz  k    S )NTFrC   i   )r   abs)rX   r   rY   rZ   r[   r   
before_rss	after_rsss           r%   _should_log_trimr`      sz      t Z+- uI&&J		)$$IY.ty:%&&*?$*FFFr=   c                    t           rt          S da t          j        dk    rdS 	 t          j                    d                                         dk    rdS t          j        d          } | j        }t          j	        g|_
        t          j        |_        |an2# t          $ r%}t                              d|           Y d}~nd}~ww xY wt          S )zEResolve glibc's malloc_trim once; return None on unsupported systems.Tr6   Nr   glibczmalloc_trim unavailable: %s)_probe_doner
   r8   r9   libc_verlowerctypesCDLLmalloc_trimc_size_targtypesc_intrestyper   loggerdebug)libctrimexcs      r%   _probe_glibc_malloc_trimrr      s      K
|wt	9q!''))W444{4  )| 9 9 92C888888889s   /B A B 
C C  C )rX   reasonr   rt   strr   float | Nonec                   t                      \  }}}}|sdS t          5  t                      }|	 ddd           dS t          j                    }||nt          |          }	| s#t          r|t          z
  |	k     r	 ddd           dS d}
| r#t          r|t          z
  |
k     r	 ddd           dS |a	 t                      }t          j                    }t          j
                      |d          }t          |          }t                      }t          j                    |z
  dz  }t          dz  a|rt          | |t          |||          rt                              d|pd	||                    d
          |                    d
          |                    d          |                    d          |                    d          |	  	         |cddd           S # t"          $ rG}t                              d|pd	t'          |          j        |           Y d}~ddd           dS d}~ww xY w# 1 swxY w Y   dS )a  Collect cycles and ask glibc to release free heap pages.

    Returns ``True`` only when ``malloc_trim(0)`` ran and reported success.
    Unsupported allocators, the config kill switch, cooldown suppression, and all
    runtime errors return ``False`` without affecting the caller.
    FNg      @r   i  r   )rX   r   rY   rZ   r[   r   zdmemory trim: reason=%s malloc_trim=%s rss_kib=%s->%s rss_anon_kib=%s->%s threads=%s duration_ms=%.1fcleanuprC   rD   rE   z#memory trim failed after %s: %s: %s)r&   
_trim_lockrr   time	monotonicr   _last_trim_monotonicrW   perf_countergccollectr   _trim_call_countr`   rm   infor   r   warningtype__name__)rX   rt   r   r   configured_cooldownr   r   rp   nowr!   _FORCE_FLOOR_SECONDSrZ   startedtrim_resultreleasedr[   duration_msrq   s                     r%   trim_memoryr      s   " 	 u 
 @ @'))<@ @ @ @ @ @ @ @ n  '  "#344 	
  	- 	#8L2Lx2W2W@ @ @ @ @ @ @ @"  #	$	 **-AAA/@ @ @ @ @ @ @ @4  #%	,..F'))GJLLL$q''KK((H+--E,..8D@K! ,'+&;    F'iJJy))IIi((JJ~..IIn--IIn--   q@ @ @ @ @ @ @ @r  	 	 	NN5#)S		"	   555A@ @ @ @ @ @ @ @r	s@ @ @ @ @ @ @ @ @ @sG   H3>H3	H30H33DG
H0)1H+H3+H00H33H7:H7)r   r   )r'   r   r   r(   )r'   r   r   r0   )r'   r   r2   r(   r   r(   )r   r4   )N)r?   r@   r   rA   )rX   r   r   r0   rY   r0   rZ   rA   r[   rA   r   r(   r   r   )r   r	   )rX   r   rt   ru   r   rv   r   r   )&__doc__
__future__r   rf   r~   loggingr9   r8   rJ   rz   collections.abcr   pathlibr   typingr   	getLoggerr   rm   r   r   r   Lockry   r|   rc   r
   __annotations__r   r&   r   r   r    r>   rW   r`   rr   r   r<   r=   r%   <module>r      s     # " " " " "  				   



      $ $ $ $ $ $            		8	$	$   !$ Y^
 ,0 0 0 0 0 ! ! ! !H) ) ) )$ $ $ $          2G G G G"   . %)	V V V V V V V Vr=   