freecache 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #! /usr/bin/python2
  2. # -*- coding: utf-8 -*-
  3. #
  4. __author__='atareao'
  5. __date__ ='$06/11/2011'
  6. #
  7. # control the use of the cache
  8. #
  9. # Copyright (C) 2010 Lorenzo Carbonell
  10. # lorenzo.carbonell.cerezo@gmail.com
  11. #
  12. # This program is free software: you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation, either version 3 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. #
  25. #
  26. #
  27. import sys
  28. import os
  29. import atexit
  30. from signal import SIGTERM
  31. import shlex
  32. import subprocess
  33. import re
  34. import time
  35. def ejecuta(comando):
  36. args = shlex.split(comando)
  37. p = subprocess.Popen(args, bufsize=10000, stdout=subprocess.PIPE)
  38. valor = p.communicate()[0]
  39. return valor
  40. def s2f(value):
  41. try:
  42. val = float(value)
  43. except:
  44. val = 0.0
  45. return val
  46. def libera(used, cached):
  47. ejecuta('sync')
  48. ejecuta('/sbin/sysctl vm.drop_caches=3')
  49. total, used_new, cached_new = get_status()
  50. free = used - used_new
  51. free_cached = cached -cached_new
  52. msg = 'Free memory\namount of RAM free %s MB\namount of CACHED free %s MB'%(free,free_cached)
  53. print msg
  54. #notification = pynotify.Notification ('Free cache',msg,)
  55. #notification.show()
  56. def get_status():
  57. s = ejecuta('free -m')
  58. s = re.sub(' +',' ',s).split('\n')[1].split(' ')
  59. total = s2f(s[1])
  60. used = s2f(s[2])
  61. free = s2f(s[3])
  62. shared = s2f(s[4])
  63. buffers = s2f(s[5])
  64. cached = s2f(s[6])
  65. return total, used, cached
  66. def check():
  67. total, used, cached = get_status()
  68. if total > 0:
  69. used_p = int((used)/total*100.0)
  70. cached_p = int((cached)/total*100.0)
  71. print 'Used %s, Cached %s'%(used_p,cached_p)
  72. if (used_p + cached_p > 90 and cached_p > 15) or (used_p > 95) or (cached_p > 30):
  73. libera(used,cached)
  74. class Daemon:
  75. """
  76. A generic daemon class.
  77. Usage: subclass the Daemon class and override the run() method
  78. """
  79. def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
  80. self.stdin = stdin
  81. self.stdout = stdout
  82. self.stderr = stderr
  83. self.pidfile = pidfile
  84. def daemonize(self):
  85. """
  86. do the UNIX double-fork magic, see Stevens' "Advanced
  87. Programming in the UNIX Environment" for details (ISBN 0201563177)
  88. http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
  89. """
  90. try:
  91. pid = os.fork()
  92. if pid > 0:
  93. # exit first parent
  94. sys.exit(0)
  95. except OSError, e:
  96. sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
  97. sys.exit(1)
  98. # decouple from parent environment
  99. os.chdir("/")
  100. os.setsid()
  101. os.umask(0)
  102. # do second fork
  103. try:
  104. pid = os.fork()
  105. if pid > 0:
  106. # exit from second parent
  107. sys.exit(0)
  108. except OSError, e:
  109. sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
  110. sys.exit(1)
  111. # redirect standard file descriptors
  112. sys.stdout.flush()
  113. sys.stderr.flush()
  114. si = file(self.stdin, 'r')
  115. so = file(self.stdout, 'a+')
  116. se = file(self.stderr, 'a+', 0)
  117. os.dup2(si.fileno(), sys.stdin.fileno())
  118. os.dup2(so.fileno(), sys.stdout.fileno())
  119. os.dup2(se.fileno(), sys.stderr.fileno())
  120. # write pidfile
  121. atexit.register(self.delpid)
  122. pid = str(os.getpid())
  123. file(self.pidfile,'w+').write("%s\n" % pid)
  124. def delpid(self):
  125. os.remove(self.pidfile)
  126. def start(self):
  127. """
  128. Start the daemon
  129. """
  130. # Check for a pidfile to see if the daemon already runs
  131. try:
  132. pf = file(self.pidfile,'r')
  133. pid = int(pf.read().strip())
  134. pf.close()
  135. except IOError:
  136. pid = None
  137. if pid:
  138. message = "pidfile %s already exist. Daemon already running?\n"
  139. sys.stderr.write(message % self.pidfile)
  140. sys.exit(1)
  141. # Start the daemon
  142. self.daemonize()
  143. self.run()
  144. def stop(self):
  145. """
  146. Stop the daemon
  147. """
  148. # Get the pid from the pidfile
  149. try:
  150. pf = file(self.pidfile,'r')
  151. pid = int(pf.read().strip())
  152. pf.close()
  153. except IOError:
  154. pid = None
  155. if not pid:
  156. message = "pidfile %s does not exist. Daemon not running?\n"
  157. sys.stderr.write(message % self.pidfile)
  158. return # not an error in a restart
  159. # Try killing the daemon process
  160. try:
  161. while 1:
  162. os.kill(pid, SIGTERM)
  163. time.sleep(0.1)
  164. except OSError, err:
  165. err = str(err)
  166. if err.find("No such process") > 0:
  167. if os.path.exists(self.pidfile):
  168. os.remove(self.pidfile)
  169. else:
  170. print str(err)
  171. sys.exit(1)
  172. def restart(self):
  173. """
  174. Restart the daemon
  175. """
  176. self.stop()
  177. self.start()
  178. def run(self):
  179. """
  180. You should override this method when you subclass Daemon. It will be called after the process has been
  181. daemonized by start() or restart().
  182. """
  183. class FreeCache(Daemon):
  184. def run(self):
  185. while True:
  186. time.sleep(10)
  187. check()
  188. if __name__ == "__main__":
  189. daemon = FreeCache('/tmp/freecache.pid')
  190. if len(sys.argv) == 2:
  191. if 'start' == sys.argv[1]:
  192. daemon.start()
  193. elif 'stop' == sys.argv[1]:
  194. daemon.stop()
  195. elif 'restart' == sys.argv[1]:
  196. daemon.restart()
  197. else:
  198. print "Unknown command"
  199. sys.exit(2)
  200. sys.exit(0)
  201. else:
  202. print "usage: %s start|stop|restart" % sys.argv[0]
  203. sys.exit(2)