_damon_sysfs.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. # SPDX-License-Identifier: GPL-2.0
  2. import os
  3. ksft_skip=4
  4. sysfs_root = None
  5. with open('/proc/mounts', 'r') as f:
  6. for line in f:
  7. dev_name, mount_point, dev_fs = line.split()[:3]
  8. if dev_fs == 'sysfs':
  9. sysfs_root = '%s/kernel/mm/damon/admin' % mount_point
  10. break
  11. if sysfs_root is None:
  12. print('Seems sysfs not mounted?')
  13. exit(ksft_skip)
  14. if not os.path.exists(sysfs_root):
  15. print('Seems DAMON disabled?')
  16. exit(ksft_skip)
  17. def write_file(path, string):
  18. "Returns error string if failed, or None otherwise"
  19. string = '%s' % string
  20. try:
  21. with open(path, 'w') as f:
  22. f.write(string)
  23. except Exception as e:
  24. return '%s' % e
  25. return None
  26. def read_file(path):
  27. '''Returns the read content and error string. The read content is None if
  28. the reading failed'''
  29. try:
  30. with open(path, 'r') as f:
  31. return f.read(), None
  32. except Exception as e:
  33. return None, '%s' % e
  34. class DamosAccessPattern:
  35. size = None
  36. nr_accesses = None
  37. age = None
  38. scheme = None
  39. def __init__(self, size=None, nr_accesses=None, age=None):
  40. self.size = size
  41. self.nr_accesses = nr_accesses
  42. self.age = age
  43. if self.size is None:
  44. self.size = [0, 2**64 - 1]
  45. if self.nr_accesses is None:
  46. self.nr_accesses = [0, 2**32 - 1]
  47. if self.age is None:
  48. self.age = [0, 2**32 - 1]
  49. def sysfs_dir(self):
  50. return os.path.join(self.scheme.sysfs_dir(), 'access_pattern')
  51. def stage(self):
  52. err = write_file(
  53. os.path.join(self.sysfs_dir(), 'sz', 'min'), self.size[0])
  54. if err is not None:
  55. return err
  56. err = write_file(
  57. os.path.join(self.sysfs_dir(), 'sz', 'max'), self.size[1])
  58. if err is not None:
  59. return err
  60. err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'min'),
  61. self.nr_accesses[0])
  62. if err is not None:
  63. return err
  64. err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'max'),
  65. self.nr_accesses[1])
  66. if err is not None:
  67. return err
  68. err = write_file(
  69. os.path.join(self.sysfs_dir(), 'age', 'min'), self.age[0])
  70. if err is not None:
  71. return err
  72. err = write_file(
  73. os.path.join(self.sysfs_dir(), 'age', 'max'), self.age[1])
  74. if err is not None:
  75. return err
  76. qgoal_metric_user_input = 'user_input'
  77. qgoal_metric_some_mem_psi_us = 'some_mem_psi_us'
  78. qgoal_metrics = [qgoal_metric_user_input, qgoal_metric_some_mem_psi_us]
  79. class DamosQuotaGoal:
  80. metric = None
  81. target_value = None
  82. current_value = None
  83. nid = None
  84. effective_bytes = None
  85. quota = None # owner quota
  86. idx = None
  87. def __init__(self, metric, target_value=10000, current_value=0, nid=0):
  88. self.metric = metric
  89. self.target_value = target_value
  90. self.current_value = current_value
  91. self.nid = nid
  92. def sysfs_dir(self):
  93. return os.path.join(self.quota.sysfs_dir(), 'goals', '%d' % self.idx)
  94. def stage(self):
  95. err = write_file(os.path.join(self.sysfs_dir(), 'target_metric'),
  96. self.metric)
  97. if err is not None:
  98. return err
  99. err = write_file(os.path.join(self.sysfs_dir(), 'target_value'),
  100. self.target_value)
  101. if err is not None:
  102. return err
  103. err = write_file(os.path.join(self.sysfs_dir(), 'current_value'),
  104. self.current_value)
  105. if err is not None:
  106. return err
  107. err = write_file(os.path.join(self.sysfs_dir(), 'nid'), self.nid)
  108. if err is not None:
  109. return err
  110. return None
  111. class DamosQuota:
  112. sz = None # size quota, in bytes
  113. ms = None # time quota
  114. goals = None # quota goals
  115. reset_interval_ms = None # quota reset interval
  116. weight_sz_permil = None
  117. weight_nr_accesses_permil = None
  118. weight_age_permil = None
  119. scheme = None # owner scheme
  120. def __init__(self, sz=0, ms=0, goals=None, reset_interval_ms=0,
  121. weight_sz_permil=0, weight_nr_accesses_permil=0,
  122. weight_age_permil=0):
  123. self.sz = sz
  124. self.ms = ms
  125. self.reset_interval_ms = reset_interval_ms
  126. self.weight_sz_permil = weight_sz_permil
  127. self.weight_nr_accesses_permil = weight_nr_accesses_permil
  128. self.weight_age_permil = weight_age_permil
  129. self.goals = goals if goals is not None else []
  130. for idx, goal in enumerate(self.goals):
  131. goal.idx = idx
  132. goal.quota = self
  133. def sysfs_dir(self):
  134. return os.path.join(self.scheme.sysfs_dir(), 'quotas')
  135. def stage(self):
  136. err = write_file(os.path.join(self.sysfs_dir(), 'bytes'), self.sz)
  137. if err is not None:
  138. return err
  139. err = write_file(os.path.join(self.sysfs_dir(), 'ms'), self.ms)
  140. if err is not None:
  141. return err
  142. err = write_file(os.path.join(self.sysfs_dir(), 'reset_interval_ms'),
  143. self.reset_interval_ms)
  144. if err is not None:
  145. return err
  146. err = write_file(os.path.join(
  147. self.sysfs_dir(), 'weights', 'sz_permil'), self.weight_sz_permil)
  148. if err is not None:
  149. return err
  150. err = write_file(os.path.join(
  151. self.sysfs_dir(), 'weights', 'nr_accesses_permil'),
  152. self.weight_nr_accesses_permil)
  153. if err is not None:
  154. return err
  155. err = write_file(os.path.join(
  156. self.sysfs_dir(), 'weights', 'age_permil'), self.weight_age_permil)
  157. if err is not None:
  158. return err
  159. nr_goals_file = os.path.join(self.sysfs_dir(), 'goals', 'nr_goals')
  160. content, err = read_file(nr_goals_file)
  161. if err is not None:
  162. return err
  163. if int(content) != len(self.goals):
  164. err = write_file(nr_goals_file, len(self.goals))
  165. if err is not None:
  166. return err
  167. for goal in self.goals:
  168. err = goal.stage()
  169. if err is not None:
  170. return err
  171. return None
  172. class DamosWatermarks:
  173. metric = None
  174. interval = None
  175. high = None
  176. mid = None
  177. low = None
  178. scheme = None # owner scheme
  179. def __init__(self, metric='none', interval=0, high=0, mid=0, low=0):
  180. self.metric = metric
  181. self.interval = interval
  182. self.high = high
  183. self.mid = mid
  184. self.low = low
  185. def sysfs_dir(self):
  186. return os.path.join(self.scheme.sysfs_dir(), 'watermarks')
  187. def stage(self):
  188. err = write_file(os.path.join(self.sysfs_dir(), 'metric'), self.metric)
  189. if err is not None:
  190. return err
  191. err = write_file(os.path.join(self.sysfs_dir(), 'interval_us'),
  192. self.interval)
  193. if err is not None:
  194. return err
  195. err = write_file(os.path.join(self.sysfs_dir(), 'high'), self.high)
  196. if err is not None:
  197. return err
  198. err = write_file(os.path.join(self.sysfs_dir(), 'mid'), self.mid)
  199. if err is not None:
  200. return err
  201. err = write_file(os.path.join(self.sysfs_dir(), 'low'), self.low)
  202. if err is not None:
  203. return err
  204. class DamosFilter:
  205. type_ = None
  206. matching = None
  207. allow = None
  208. memcg_path = None
  209. addr_start = None
  210. addr_end = None
  211. target_idx = None
  212. min_ = None
  213. max_ = None
  214. idx = None
  215. filters = None # owner filters
  216. def __init__(self, type_='anon', matching=False, allow=False,
  217. memcg_path='', addr_start=0, addr_end=0, target_idx=0, min_=0,
  218. max_=0):
  219. self.type_ = type_
  220. self.matching = matching
  221. self.allow = allow
  222. self.memcg_path = memcg_path,
  223. self.addr_start = addr_start
  224. self.addr_end = addr_end
  225. self.target_idx = target_idx
  226. self.min_ = min_
  227. self.max_ = max_
  228. def sysfs_dir(self):
  229. return os.path.join(self.filters.sysfs_dir(), '%d' % self.idx)
  230. def stage(self):
  231. err = write_file(os.path.join(self.sysfs_dir(), 'type'), self.type_)
  232. if err is not None:
  233. return err
  234. err = write_file(os.path.join(self.sysfs_dir(), 'matching'),
  235. self.matching)
  236. if err is not None:
  237. return err
  238. err = write_file(os.path.join(self.sysfs_dir(), 'allow'), self.allow)
  239. if err is not None:
  240. return err
  241. err = write_file(os.path.join(self.sysfs_dir(), 'memcg_path'),
  242. self.memcg_path)
  243. if err is not None:
  244. return err
  245. err = write_file(os.path.join(self.sysfs_dir(), 'addr_start'),
  246. self.addr_start)
  247. if err is not None:
  248. return err
  249. err = write_file(os.path.join(self.sysfs_dir(), 'addr_end'),
  250. self.addr_end)
  251. if err is not None:
  252. return err
  253. err = write_file(os.path.join(self.sysfs_dir(), 'damon_target_idx'),
  254. self.target_idx)
  255. if err is not None:
  256. return err
  257. err = write_file(os.path.join(self.sysfs_dir(), 'min'), self.min_)
  258. if err is not None:
  259. return err
  260. err = write_file(os.path.join(self.sysfs_dir(), 'max'), self.max_)
  261. if err is not None:
  262. return err
  263. return None
  264. class DamosFilters:
  265. name = None
  266. filters = None
  267. scheme = None # owner scheme
  268. def __init__(self, name, filters=[]):
  269. self.name = name
  270. self.filters = filters
  271. for idx, filter_ in enumerate(self.filters):
  272. filter_.idx = idx
  273. filter_.filters = self
  274. def sysfs_dir(self):
  275. return os.path.join(self.scheme.sysfs_dir(), self.name)
  276. def stage(self):
  277. err = write_file(os.path.join(self.sysfs_dir(), 'nr_filters'),
  278. len(self.filters))
  279. if err is not None:
  280. return err
  281. for filter_ in self.filters:
  282. err = filter_.stage()
  283. if err is not None:
  284. return err
  285. return None
  286. class DamosDest:
  287. id = None
  288. weight = None
  289. idx = None
  290. dests = None # owner dests
  291. def __init__(self, id=0, weight=0):
  292. self.id = id
  293. self.weight = weight
  294. def sysfs_dir(self):
  295. return os.path.join(self.dests.sysfs_dir(), '%d' % self.idx)
  296. def stage(self):
  297. err = write_file(os.path.join(self.sysfs_dir(), 'id'), self.id)
  298. if err is not None:
  299. return err
  300. err = write_file(os.path.join(self.sysfs_dir(), 'weight'), self.weight)
  301. if err is not None:
  302. return err
  303. return None
  304. class DamosDests:
  305. dests = None
  306. scheme = None # owner scheme
  307. def __init__(self, dests=[]):
  308. self.dests = dests
  309. for idx, dest in enumerate(self.dests):
  310. dest.idx = idx
  311. dest.dests = self
  312. def sysfs_dir(self):
  313. return os.path.join(self.scheme.sysfs_dir(), 'dests')
  314. def stage(self):
  315. err = write_file(os.path.join(self.sysfs_dir(), 'nr_dests'),
  316. len(self.dests))
  317. if err is not None:
  318. return err
  319. for dest in self.dests:
  320. err = dest.stage()
  321. if err is not None:
  322. return err
  323. return None
  324. class DamosStats:
  325. nr_tried = None
  326. sz_tried = None
  327. nr_applied = None
  328. sz_applied = None
  329. qt_exceeds = None
  330. def __init__(self, nr_tried, sz_tried, nr_applied, sz_applied, qt_exceeds):
  331. self.nr_tried = nr_tried
  332. self.sz_tried = sz_tried
  333. self.nr_applied = nr_applied
  334. self.sz_applied = sz_applied
  335. self.qt_exceeds = qt_exceeds
  336. class DamosTriedRegion:
  337. def __init__(self, start, end, nr_accesses, age):
  338. self.start = start
  339. self.end = end
  340. self.nr_accesses = nr_accesses
  341. self.age = age
  342. class Damos:
  343. action = None
  344. access_pattern = None
  345. quota = None
  346. watermarks = None
  347. core_filters = None
  348. ops_filters = None
  349. filters = None
  350. apply_interval_us = None
  351. target_nid = None
  352. dests = None
  353. idx = None
  354. context = None
  355. tried_bytes = None
  356. stats = None
  357. tried_regions = None
  358. def __init__(self, action='stat', access_pattern=DamosAccessPattern(),
  359. quota=DamosQuota(), watermarks=DamosWatermarks(),
  360. core_filters=[], ops_filters=[], filters=[], target_nid=0,
  361. dests=DamosDests(), apply_interval_us=0):
  362. self.action = action
  363. self.access_pattern = access_pattern
  364. self.access_pattern.scheme = self
  365. self.quota = quota
  366. self.quota.scheme = self
  367. self.watermarks = watermarks
  368. self.watermarks.scheme = self
  369. self.core_filters = DamosFilters(name='core_filters',
  370. filters=core_filters)
  371. self.core_filters.scheme = self
  372. self.ops_filters = DamosFilters(name='ops_filters',
  373. filters=ops_filters)
  374. self.ops_filters.scheme = self
  375. self.filters = DamosFilters(name='filters', filters=filters)
  376. self.filters.scheme = self
  377. self.target_nid = target_nid
  378. self.dests = dests
  379. self.dests.scheme = self
  380. self.apply_interval_us = apply_interval_us
  381. def sysfs_dir(self):
  382. return os.path.join(
  383. self.context.sysfs_dir(), 'schemes', '%d' % self.idx)
  384. def stage(self):
  385. err = write_file(os.path.join(self.sysfs_dir(), 'action'), self.action)
  386. if err is not None:
  387. return err
  388. err = self.access_pattern.stage()
  389. if err is not None:
  390. return err
  391. err = write_file(os.path.join(self.sysfs_dir(), 'apply_interval_us'),
  392. '%d' % self.apply_interval_us)
  393. if err is not None:
  394. return err
  395. err = self.quota.stage()
  396. if err is not None:
  397. return err
  398. err = self.watermarks.stage()
  399. if err is not None:
  400. return err
  401. err = self.core_filters.stage()
  402. if err is not None:
  403. return err
  404. err = self.ops_filters.stage()
  405. if err is not None:
  406. return err
  407. err = self.filters.stage()
  408. if err is not None:
  409. return err
  410. err = write_file(os.path.join(self.sysfs_dir(), 'target_nid'), '%d' %
  411. self.target_nid)
  412. if err is not None:
  413. return err
  414. err = self.dests.stage()
  415. if err is not None:
  416. return err
  417. class DamonTarget:
  418. pid = None
  419. obsolete = None
  420. # todo: Support target regions if test is made
  421. idx = None
  422. context = None
  423. def __init__(self, pid, obsolete=False):
  424. self.pid = pid
  425. self.obsolete = obsolete
  426. def sysfs_dir(self):
  427. return os.path.join(
  428. self.context.sysfs_dir(), 'targets', '%d' % self.idx)
  429. def stage(self):
  430. err = write_file(
  431. os.path.join(self.sysfs_dir(), 'regions', 'nr_regions'), '0')
  432. if err is not None:
  433. return err
  434. err = write_file(
  435. os.path.join(self.sysfs_dir(), 'pid_target'), self.pid)
  436. if err is not None:
  437. return err
  438. return write_file(
  439. os.path.join(self.sysfs_dir(), 'obsolete_target'),
  440. 'Y' if self.obsolete else 'N')
  441. class IntervalsGoal:
  442. access_bp = None
  443. aggrs = None
  444. min_sample_us = None
  445. max_sample_us = None
  446. attrs = None # owner DamonAttrs
  447. def __init__(self, access_bp=0, aggrs=0, min_sample_us=0, max_sample_us=0):
  448. self.access_bp = access_bp
  449. self.aggrs = aggrs
  450. self.min_sample_us = min_sample_us
  451. self.max_sample_us = max_sample_us
  452. def sysfs_dir(self):
  453. return os.path.join(self.attrs.interval_sysfs_dir(), 'intervals_goal')
  454. def stage(self):
  455. err = write_file(
  456. os.path.join(self.sysfs_dir(), 'access_bp'), self.access_bp)
  457. if err is not None:
  458. return err
  459. err = write_file(os.path.join(self.sysfs_dir(), 'aggrs'), self.aggrs)
  460. if err is not None:
  461. return err
  462. err = write_file(os.path.join(self.sysfs_dir(), 'min_sample_us'),
  463. self.min_sample_us)
  464. if err is not None:
  465. return err
  466. err = write_file(os.path.join(self.sysfs_dir(), 'max_sample_us'),
  467. self.max_sample_us)
  468. if err is not None:
  469. return err
  470. return None
  471. class DamonAttrs:
  472. sample_us = None
  473. aggr_us = None
  474. intervals_goal = None
  475. update_us = None
  476. min_nr_regions = None
  477. max_nr_regions = None
  478. context = None
  479. def __init__(self, sample_us=5000, aggr_us=100000,
  480. intervals_goal=IntervalsGoal(), update_us=1000000,
  481. min_nr_regions=10, max_nr_regions=1000):
  482. self.sample_us = sample_us
  483. self.aggr_us = aggr_us
  484. self.intervals_goal = intervals_goal
  485. self.intervals_goal.attrs = self
  486. self.update_us = update_us
  487. self.min_nr_regions = min_nr_regions
  488. self.max_nr_regions = max_nr_regions
  489. def interval_sysfs_dir(self):
  490. return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',
  491. 'intervals')
  492. def nr_regions_range_sysfs_dir(self):
  493. return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',
  494. 'nr_regions')
  495. def stage(self):
  496. err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'),
  497. self.sample_us)
  498. if err is not None:
  499. return err
  500. err = write_file(os.path.join(self.interval_sysfs_dir(), 'aggr_us'),
  501. self.aggr_us)
  502. if err is not None:
  503. return err
  504. err = self.intervals_goal.stage()
  505. if err is not None:
  506. return err
  507. err = write_file(os.path.join(self.interval_sysfs_dir(), 'update_us'),
  508. self.update_us)
  509. if err is not None:
  510. return err
  511. err = write_file(
  512. os.path.join(self.nr_regions_range_sysfs_dir(), 'min'),
  513. self.min_nr_regions)
  514. if err is not None:
  515. return err
  516. err = write_file(
  517. os.path.join(self.nr_regions_range_sysfs_dir(), 'max'),
  518. self.max_nr_regions)
  519. if err is not None:
  520. return err
  521. class DamonCtx:
  522. ops = None
  523. monitoring_attrs = None
  524. targets = None
  525. schemes = None
  526. kdamond = None
  527. idx = None
  528. def __init__(self, ops='paddr', monitoring_attrs=DamonAttrs(), targets=[],
  529. schemes=[]):
  530. self.ops = ops
  531. self.monitoring_attrs = monitoring_attrs
  532. self.monitoring_attrs.context = self
  533. self.targets = targets
  534. for idx, target in enumerate(self.targets):
  535. target.idx = idx
  536. target.context = self
  537. self.schemes = schemes
  538. for idx, scheme in enumerate(self.schemes):
  539. scheme.idx = idx
  540. scheme.context = self
  541. def sysfs_dir(self):
  542. return os.path.join(self.kdamond.sysfs_dir(), 'contexts',
  543. '%d' % self.idx)
  544. def stage(self):
  545. err = write_file(
  546. os.path.join(self.sysfs_dir(), 'operations'), self.ops)
  547. if err is not None:
  548. return err
  549. err = self.monitoring_attrs.stage()
  550. if err is not None:
  551. return err
  552. nr_targets_file = os.path.join(
  553. self.sysfs_dir(), 'targets', 'nr_targets')
  554. content, err = read_file(nr_targets_file)
  555. if err is not None:
  556. return err
  557. if int(content) != len(self.targets):
  558. err = write_file(nr_targets_file, '%d' % len(self.targets))
  559. if err is not None:
  560. return err
  561. for target in self.targets:
  562. err = target.stage()
  563. if err is not None:
  564. return err
  565. nr_schemes_file = os.path.join(
  566. self.sysfs_dir(), 'schemes', 'nr_schemes')
  567. content, err = read_file(nr_schemes_file)
  568. if err is not None:
  569. return err
  570. if int(content) != len(self.schemes):
  571. err = write_file(nr_schemes_file, '%d' % len(self.schemes))
  572. if err is not None:
  573. return err
  574. for scheme in self.schemes:
  575. err = scheme.stage()
  576. if err is not None:
  577. return err
  578. return None
  579. class Kdamond:
  580. state = None
  581. pid = None
  582. contexts = None
  583. idx = None # index of this kdamond between siblings
  584. kdamonds = None # parent
  585. def __init__(self, contexts=[]):
  586. self.contexts = contexts
  587. for idx, context in enumerate(self.contexts):
  588. context.idx = idx
  589. context.kdamond = self
  590. def sysfs_dir(self):
  591. return os.path.join(self.kdamonds.sysfs_dir(), '%d' % self.idx)
  592. def start(self):
  593. nr_contexts_file = os.path.join(self.sysfs_dir(),
  594. 'contexts', 'nr_contexts')
  595. content, err = read_file(nr_contexts_file)
  596. if err is not None:
  597. return err
  598. if int(content) != len(self.contexts):
  599. err = write_file(nr_contexts_file, '%d' % len(self.contexts))
  600. if err is not None:
  601. return err
  602. for context in self.contexts:
  603. err = context.stage()
  604. if err is not None:
  605. return err
  606. err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'on')
  607. if err is not None:
  608. return err
  609. self.pid, err = read_file(os.path.join(self.sysfs_dir(), 'pid'))
  610. return err
  611. def stop(self):
  612. err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'off')
  613. return err
  614. def update_schemes_tried_regions(self):
  615. err = write_file(os.path.join(self.sysfs_dir(), 'state'),
  616. 'update_schemes_tried_regions')
  617. if err is not None:
  618. return err
  619. for context in self.contexts:
  620. for scheme in context.schemes:
  621. tried_regions = []
  622. tried_regions_dir = os.path.join(
  623. scheme.sysfs_dir(), 'tried_regions')
  624. region_indices = []
  625. for filename in os.listdir(
  626. os.path.join(scheme.sysfs_dir(), 'tried_regions')):
  627. tried_region_dir = os.path.join(tried_regions_dir, filename)
  628. if not os.path.isdir(tried_region_dir):
  629. continue
  630. region_indices.append(int(filename))
  631. for region_idx in sorted(region_indices):
  632. tried_region_dir = os.path.join(tried_regions_dir,
  633. '%d' % region_idx)
  634. region_values = []
  635. for f in ['start', 'end', 'nr_accesses', 'age']:
  636. content, err = read_file(
  637. os.path.join(tried_region_dir, f))
  638. if err is not None:
  639. return err
  640. region_values.append(int(content))
  641. tried_regions.append(DamosTriedRegion(*region_values))
  642. scheme.tried_regions = tried_regions
  643. def update_schemes_tried_bytes(self):
  644. err = write_file(os.path.join(self.sysfs_dir(), 'state'),
  645. 'update_schemes_tried_bytes')
  646. if err is not None:
  647. return err
  648. for context in self.contexts:
  649. for scheme in context.schemes:
  650. content, err = read_file(os.path.join(scheme.sysfs_dir(),
  651. 'tried_regions', 'total_bytes'))
  652. if err is not None:
  653. return err
  654. scheme.tried_bytes = int(content)
  655. def update_schemes_stats(self):
  656. err = write_file(os.path.join(self.sysfs_dir(), 'state'),
  657. 'update_schemes_stats')
  658. if err is not None:
  659. return err
  660. for context in self.contexts:
  661. for scheme in context.schemes:
  662. stat_values = []
  663. for stat in ['nr_tried', 'sz_tried', 'nr_applied',
  664. 'sz_applied', 'qt_exceeds']:
  665. content, err = read_file(
  666. os.path.join(scheme.sysfs_dir(), 'stats', stat))
  667. if err is not None:
  668. return err
  669. stat_values.append(int(content))
  670. scheme.stats = DamosStats(*stat_values)
  671. def update_schemes_effective_quotas(self):
  672. err = write_file(os.path.join(self.sysfs_dir(), 'state'),
  673. 'update_schemes_effective_quotas')
  674. if err is not None:
  675. return err
  676. for context in self.contexts:
  677. for scheme in context.schemes:
  678. for goal in scheme.quota.goals:
  679. content, err = read_file(
  680. os.path.join(scheme.quota.sysfs_dir(),
  681. 'effective_bytes'))
  682. if err is not None:
  683. return err
  684. goal.effective_bytes = int(content)
  685. return None
  686. def commit(self):
  687. nr_contexts_file = os.path.join(self.sysfs_dir(),
  688. 'contexts', 'nr_contexts')
  689. content, err = read_file(nr_contexts_file)
  690. if err is not None:
  691. return err
  692. if int(content) != len(self.contexts):
  693. err = write_file(nr_contexts_file, '%d' % len(self.contexts))
  694. if err is not None:
  695. return err
  696. for context in self.contexts:
  697. err = context.stage()
  698. if err is not None:
  699. return err
  700. err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'commit')
  701. return err
  702. def commit_schemes_quota_goals(self):
  703. for context in self.contexts:
  704. for scheme in context.schemes:
  705. for goal in scheme.quota.goals:
  706. err = goal.stage()
  707. if err is not None:
  708. print('commit_schemes_quota_goals failed stagign: %s'%
  709. err)
  710. exit(1)
  711. return write_file(os.path.join(self.sysfs_dir(), 'state'),
  712. 'commit_schemes_quota_goals')
  713. class Kdamonds:
  714. kdamonds = []
  715. def __init__(self, kdamonds=[]):
  716. self.kdamonds = kdamonds
  717. for idx, kdamond in enumerate(self.kdamonds):
  718. kdamond.idx = idx
  719. kdamond.kdamonds = self
  720. def sysfs_dir(self):
  721. return os.path.join(sysfs_root, 'kdamonds')
  722. def start(self):
  723. err = write_file(os.path.join(self.sysfs_dir(), 'nr_kdamonds'),
  724. '%s' % len(self.kdamonds))
  725. if err is not None:
  726. return err
  727. for kdamond in self.kdamonds:
  728. err = kdamond.start()
  729. if err is not None:
  730. return err
  731. return None
  732. def stop(self):
  733. for kdamond in self.kdamonds:
  734. err = kdamond.stop()
  735. if err is not None:
  736. return err
  737. return None