devterm-a04-gearbox 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!/usr/bin/python3
  2. import glob
  3. import os
  4. import sys,getopt
  5. import subprocess
  6. import time
  7. # The gearings below were picked based on various tests by the ClockworkPi devs.
  8. # The maximum-performance maximum-power gearing is present for completeness, but
  9. # shouldn't be needed for most uses.
  10. #
  11. # You can customise the gearings by editing the list below. The valid freqencies
  12. # for CPU <N> can be looked up here (substituting for <N>):
  13. # /sys/devices/system/cpu/cpu<N>/cpufreq/scaling_available_frequencies
  14. #
  15. #
  16. # Gears are numbered in-order, starting from 1.
  17. # It's up to you to ensure that they are sorted by performance :)
  18. def gears():
  19. return [
  20. gear(
  21. little=(720000,),
  22. use="simple writing tasks with long battery life"),
  23. gear(
  24. little=(888000,) * 2,
  25. use="browsing most websites with long battery life"),
  26. gear(
  27. little=(1080000,) * 3,
  28. use="most 2D games and emulators"),
  29. gear(
  30. little=(1488000,) * 4,
  31. use="playing videos and 3D games"),
  32. #gear(
  33. # little=(1800000,) * 4,
  34. # use="max performance, max power (usage)"),
  35. ]
  36. #GPU_GOV_SIMPLE = "simple_ondemand"
  37. #GPU_GOV_PERF = "performance"
  38. # Helper to convert the concise gear format above into a full description.
  39. def gear(
  40. little=(0, 0, 0, 0),
  41. gpu_freq=200000000,
  42. use="",
  43. ):
  44. # Extend to 4 little (matching the A04).
  45. assert len(little) <= 4
  46. cpu = little + (0,) * (4 - len(little))
  47. # At least one CPU must be enabled
  48. assert sum(cpu) > 0
  49. return {
  50. "cpu": cpu,
  51. "use": use,
  52. }
  53. # We placed gears() at the top of the file to make it easier to find and edit.
  54. # Now that we've defined the helpers it needs, evaluate the gears.
  55. gears = gears()
  56. def load_gear(gear):
  57. return gears[gear - 1]
  58. cur_stat = []
  59. cur_stat.append("+-----------------------------------+")
  60. cur_stat.append("| Cortex-A53 |")
  61. cur_stat.append("+--------+--------+--------+--------+")
  62. cur_stat.append("| CPU 0 | CPU 1 | CPU 2 | CPU 3 |")
  63. cur_stat.append("+--------+--------+--------+--------+")
  64. cur_stat.append("| 600MHz | OFF | OFF | OFF |") #5
  65. cur_stat.append("+--------+--------+--------+--------+")
  66. def isDigit(x):
  67. try:
  68. float(x)
  69. return True
  70. except ValueError:
  71. return False
  72. class A04:
  73. cpus = []
  74. cpu_scaling_governor= "ondemand"
  75. gear = load_gear(1) # 1-5
  76. null_out = "2>/dev/null"
  77. def __init__(self):
  78. self.cpus = []
  79. self.init_cpu_infos()
  80. self.cpu_total_count = len(self.cpus)
  81. def init_cpu_infos(self):
  82. self.cpus = glob.glob('/sys/devices/system/cpu/cpu[0-9]')
  83. self.cpus.sort()
  84. def get_cpu_gov(self):
  85. cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
  86. gov = ""
  87. with open(cpu_gov_path,"r") as f: gov = f.read().strip()
  88. return gov
  89. def set_cpu_gov0( self,gov):
  90. cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
  91. try:
  92. subprocess.run( "echo %s | sudo tee %s " %(gov,cpu_gov_path),shell=True,stdout=subprocess.DEVNULL)
  93. except:
  94. print("set cpu governor failed")
  95. def get_cpu_on_off(self,cpu_num):
  96. cpu_onoff_file = "/sys/devices/system/cpu/cpu%d/online" % cpu_num
  97. onoff = "0"
  98. max_freq = "0"
  99. with open(cpu_onoff_file,"r") as f: onoff = f.read().strip()
  100. if onoff == "1":
  101. cpu_max_freq_file = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq" % cpu_num
  102. with open(cpu_max_freq_file,"r") as f: max_freq = f.read().strip()
  103. mhz = int(max_freq)/1000
  104. return "%dMhz" % mhz
  105. return "OFF"
  106. def set_cpu_on_off(self,cpu_num,onoff):
  107. cpu_onoff_file = "/sys/devices/system/cpu/cpu%d/online" % cpu_num
  108. try:
  109. #print("echo %d | sudo tee %s" %(onoff,cpu_onoff_file) )
  110. subprocess.run( "echo %d | sudo tee %s" %(onoff,cpu_onoff_file),shell=True,stdout=subprocess.DEVNULL)
  111. except:
  112. print("set cpu %d on off failed" % cpu_num)
  113. def set_cpu_max_freq(self,cpu_num,max_freq):
  114. cpu_max_freq_file = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq" % cpu_num
  115. try:
  116. subprocess.run( "echo %d | sudo tee %s" %(max_freq,cpu_max_freq_file),shell=True,stdout=subprocess.DEVNULL)
  117. except:
  118. print("set cpu %d max freq failed" % cpu_num)
  119. def get_gpu_freq(self):
  120. gpu_sys_path = "/sys/devices/platform/ff9a0000.gpu/devfreq/ff9a0000.gpu"
  121. gpu_freq_path = os.path.join(gpu_sys_path,"max_freq")
  122. freq = ""
  123. with open(gpu_freq_path,"r") as f: freq = f.read().strip()
  124. mhz = int(freq)/1000000
  125. return "%dMHz" % mhz
  126. def set_gpu(self,gov,hz):
  127. gpu_sys_path = "/sys/devices/platform/ff9a0000.gpu/devfreq/ff9a0000.gpu"
  128. gpu_gov_path = os.path.join(gpu_sys_path,"governor")
  129. gpu_freq_path = os.path.join(gpu_sys_path,"max_freq")
  130. try:
  131. subprocess.run("echo %s | sudo tee %s" %(gov,gpu_gov_path),shell=True,stdout=subprocess.DEVNULL)
  132. subprocess.run("echo %d | sudo tee %s" %(hz, gpu_freq_path),shell=True,stdout=subprocess.DEVNULL)
  133. except:
  134. print("set gpu failed")
  135. def print_cpu_gov(self):
  136. print("CPU Governor: %s" % self.get_cpu_gov())
  137. def print_cur_status(self):
  138. global cur_stat
  139. stat_str = "|%s|%s|%s|%s|"
  140. cpu0 = self.get_cpu_on_off(0).center(8)[:8]
  141. cpu1 = self.get_cpu_on_off(1).center(8)[:8]
  142. cpu2 = self.get_cpu_on_off(2).center(8)[:8]
  143. cpu3 = self.get_cpu_on_off(3).center(8)[:8]
  144. #gpu = self.get_gpu_freq().center(11)[:11]
  145. table_str = stat_str %(cpu0,cpu1,cpu2,cpu3)
  146. print("\nCurrent Status:")
  147. for idx,val in enumerate(cur_stat):
  148. if idx == 5:
  149. print(table_str)
  150. else:
  151. print(val)
  152. self.print_cpu_gov()
  153. def set_gear(self,g):
  154. self.gear = load_gear(g)
  155. for (cpu, freq) in enumerate(self.gear["cpu"]):
  156. enabled = freq > 0
  157. self.set_cpu_on_off(cpu, int(enabled))
  158. if enabled:
  159. self.set_cpu_max_freq(cpu, freq)
  160. #self.set_gpu(self.gear["gpu_gov"], self.gear["gpu_freq"])
  161. # TODO: Generalise this
  162. self.set_cpu_gov0(self.cpu_scaling_governor)
  163. def print_gear_map(gear):
  164. print(" +-----------------------------------+")
  165. print(" | Cortex-A53 |")
  166. print(" +--------+--------+--------+--------+")
  167. print(" | CPU 0 | CPU 1 | CPU 2 | CPU 3 |")
  168. div = "+---+--------+--------+--------+--------+"
  169. print(div)
  170. def freq(khz):
  171. mhz = khz/1000
  172. if mhz >= 1000:
  173. return "%d MHz" % mhz
  174. elif mhz > 0:
  175. return " %d MHz" % mhz
  176. else:
  177. return " OFF "
  178. for idx, val in enumerate(gears):
  179. g = idx + 1
  180. selected = g == gear
  181. print("|%s|%s|%s" % (("*%s*" if selected else " %s ") % g,"|".join([freq(cpu) for cpu in val["cpu"]])," <===" if selected else "",))
  182. print(div)
  183. def print_help_msg():
  184. print("Usage: devterm-a04-gearbox [OPTION]...")
  185. print("Show or set the CPU operating frequency,online status and GPU operating frequency for DevTerm A04.")
  186. print()
  187. print(" -s, --set [n] set a speed mode between the number 1-%d:" % len(gears))
  188. for (i, _) in enumerate(gears):
  189. print(" %d for %s." % (i + 1, gears[i]["use"]))
  190. print()
  191. print("Examples:")
  192. # TODO: Generate this example
  193. print("Set to mode 1, single core @720MHz(max)")
  194. print(" $ devterm-a04-gearbox -s 1")
  195. def is_root():
  196. return os.geteuid() == 0
  197. def main(argv):
  198. gear = 1
  199. try:
  200. opts, args = getopt.getopt(argv,"hs:",["set="])
  201. except getopt.GetoptError:
  202. print_help_msg()
  203. sys.exit(2)
  204. for opt, arg in opts:
  205. if opt == '-h':
  206. print_help_msg()
  207. sys.exit()
  208. elif opt in ("-s","--set"):
  209. if(isDigit(arg)):
  210. gear = int(arg)
  211. if gear not in range(1, len(gears) + 1):
  212. print("illegal input: mode range 1-%d" % len(gears))
  213. sys.exit(-1)
  214. DT = A04()
  215. if len(argv) == 0:
  216. DT.print_cur_status()
  217. sys.exit(0)
  218. DT = A04()
  219. if is_root():
  220. DT.set_gear(gear)
  221. print_gear_map(gear)
  222. DT.print_cpu_gov()
  223. else:
  224. print("Require super user privilege to set mode,try run it with sudo")
  225. sys.exit(1)
  226. if __name__ == "__main__":
  227. main(sys.argv[1:])