damo 3.3.2__tar.gz → 3.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. {damo-3.3.2 → damo-3.3.4}/PKG-INFO +5 -5
  2. {damo-3.3.2 → damo-3.3.4}/README.md +4 -4
  3. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_records.py +40 -0
  4. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon.py +68 -5
  5. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon_args.py +93 -30
  6. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon_features.py +16 -0
  7. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon_sysfs.py +44 -2
  8. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_attrs.py +3 -93
  9. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_version.py +1 -1
  10. {damo-3.3.2 → damo-3.3.4}/src/damo.egg-info/PKG-INFO +5 -5
  11. {damo-3.3.2 → damo-3.3.4}/pyproject.toml +0 -0
  12. {damo-3.3.2 → damo-3.3.4}/setup.cfg +0 -0
  13. {damo-3.3.2 → damo-3.3.4}/setup.py +0 -0
  14. {damo-3.3.2 → damo-3.3.4}/src/damo/__init__.py +0 -0
  15. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_ascii_color.py +0 -0
  16. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_deprecated.py +0 -0
  17. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_deprecation_notice.py +0 -0
  18. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_dist.py +0 -0
  19. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_fmt_str.py +0 -0
  20. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_fs.py +0 -0
  21. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_print.py +0 -0
  22. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_subcmds.py +0 -0
  23. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_subproc.py +0 -0
  24. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_sysinfo.py +0 -0
  25. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_trace.py +0 -0
  26. {damo-3.3.2 → damo-3.3.4}/src/damo/_damo_yaml.py +0 -0
  27. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon_dbgfs.py +0 -0
  28. {damo-3.3.2 → damo-3.3.4}/src/damo/_damon_modules.py +0 -0
  29. {damo-3.3.2 → damo-3.3.4}/src/damo/damo.py +0 -0
  30. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_adjust.py +0 -0
  31. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_args.py +0 -0
  32. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_args_accesses_filter.py +0 -0
  33. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_args_accesses_format.py +0 -0
  34. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_args_damon.py +0 -0
  35. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_convert_record_format.py +0 -0
  36. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_diagnose.py +0 -0
  37. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_features.py +0 -0
  38. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_help.py +0 -0
  39. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_help_access_filter_options.py +0 -0
  40. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_help_access_format_options.py +0 -0
  41. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_help_damon_param_options.py +0 -0
  42. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_lru_sort.py +0 -0
  43. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_module.py +0 -0
  44. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_module_general.py +0 -0
  45. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_module_stat.py +0 -0
  46. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_monitor.py +0 -0
  47. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_nr_regions.py +0 -0
  48. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_pa_layout.py +0 -0
  49. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_reclaim.py +0 -0
  50. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_record.py +0 -0
  51. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_record_info.py +0 -0
  52. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_replay.py +0 -0
  53. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report.py +0 -0
  54. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_access.py +0 -0
  55. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_damon.py +0 -0
  56. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_footprint.py +0 -0
  57. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_heatmap.py +0 -0
  58. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_holistic.py +0 -0
  59. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_pa_layout.py +0 -0
  60. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_profile.py +0 -0
  61. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_record_info.py +0 -0
  62. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_sysinfo.py +0 -0
  63. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_times.py +0 -0
  64. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_report_trace.py +0 -0
  65. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_schemes.py +0 -0
  66. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_setup_cli_completion.py +0 -0
  67. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_start.py +0 -0
  68. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_stop.py +0 -0
  69. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_tune.py +0 -0
  70. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_validate.py +0 -0
  71. {damo-3.3.2 → damo-3.3.4}/src/damo/damo_wss.py +0 -0
  72. {damo-3.3.2 → damo-3.3.4}/src/damo.egg-info/SOURCES.txt +0 -0
  73. {damo-3.3.2 → damo-3.3.4}/src/damo.egg-info/dependency_links.txt +0 -0
  74. {damo-3.3.2 → damo-3.3.4}/src/damo.egg-info/entry_points.txt +0 -0
  75. {damo-3.3.2 → damo-3.3.4}/src/damo.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: damo
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: DAMON user-space tool
5
5
  Home-page: https://github.com/damonitor/damo
6
6
  Author: SeongJae Park
@@ -71,7 +71,7 @@ The second and last commands will show the access pattern of your workload,
71
71
  like below:
72
72
 
73
73
  ![masim_stairs_snapshot](images/masim_stairs_snapshot.png)
74
- ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.2/images/masim_stairs_heatmap_ascii.png)
74
+ ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.4/images/masim_stairs_heatmap_ascii.png)
75
75
 
76
76
 
77
77
  FAQs
@@ -90,7 +90,7 @@ Where can I get more detailed usage?
90
90
  ------------------------------------
91
91
 
92
92
  The below sections provide quick introductions for `damo`'s major features.
93
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
93
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
94
94
 
95
95
 
96
96
  What does the version numbers mean?
@@ -115,7 +115,7 @@ We try our best to make `damo` stable and doesn't introduce regressions to
115
115
  users. However, nothing goes forever. Sometimes, some features will be
116
116
  deprecated. Some features will have longer support more than others.
117
117
 
118
- In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) and not explicitly
118
+ In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) and not explicitly
119
119
  marked as experimental will be better supported, and provides at least three
120
120
  months of deprecation grace period. Within the grace period, users can ask
121
121
  extension of the support. Even after the grace period, please reach out to
@@ -138,7 +138,7 @@ Quick Intro for Major Features
138
138
  ==============================
139
139
 
140
140
  Below are quick introductions for `damo`'s major features.
141
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
141
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
142
142
 
143
143
 
144
144
  Snapshot Data Access Pattern
@@ -47,7 +47,7 @@ The second and last commands will show the access pattern of your workload,
47
47
  like below:
48
48
 
49
49
  ![masim_stairs_snapshot](images/masim_stairs_snapshot.png)
50
- ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.2/images/masim_stairs_heatmap_ascii.png)
50
+ ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.4/images/masim_stairs_heatmap_ascii.png)
51
51
 
52
52
 
53
53
  FAQs
@@ -66,7 +66,7 @@ Where can I get more detailed usage?
66
66
  ------------------------------------
67
67
 
68
68
  The below sections provide quick introductions for `damo`'s major features.
69
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
69
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
70
70
 
71
71
 
72
72
  What does the version numbers mean?
@@ -91,7 +91,7 @@ We try our best to make `damo` stable and doesn't introduce regressions to
91
91
  users. However, nothing goes forever. Sometimes, some features will be
92
92
  deprecated. Some features will have longer support more than others.
93
93
 
94
- In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) and not explicitly
94
+ In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) and not explicitly
95
95
  marked as experimental will be better supported, and provides at least three
96
96
  months of deprecation grace period. Within the grace period, users can ask
97
97
  extension of the support. Even after the grace period, please reach out to
@@ -114,7 +114,7 @@ Quick Intro for Major Features
114
114
  ==============================
115
115
 
116
116
  Below are quick introductions for `damo`'s major features.
117
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
117
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
118
118
 
119
119
 
120
120
  Snapshot Data Access Pattern
@@ -246,6 +246,28 @@ class DamonRecord:
246
246
  self.snapshots += other.snapshots
247
247
  self.snapshots.sort(key=lambda s: s.start_time)
248
248
 
249
+ class DamoRecords:
250
+ kdamonds = None # list of _damon.Kdamond
251
+ records = None # list of DamonRecord
252
+
253
+ def __init__(self, kdamonds, records):
254
+ if kdamonds is None:
255
+ kdamonds = []
256
+ if records is None:
257
+ records = []
258
+ self.kdamonds = kdamonds
259
+ self.records = records
260
+
261
+ @classmethod
262
+ def from_kvpairs(self, kv):
263
+ return DamoRecords(kdamonds=kv['kdamonds'], records=kv['records'])
264
+
265
+ def to_kvpairs(self, raw=False):
266
+ return collections.OrderedDict([
267
+ ('kdamonds', [k.to_kvapairs(raw=raw) for k in self.kdamonds]),
268
+ ('records', [r.to_kvpairs(raw=raw) for r in self.records]),
269
+ ])
270
+
249
271
  # for monitoring results manipulation
250
272
 
251
273
  def merge_records(records):
@@ -539,6 +561,11 @@ def parse_perf_damon_record(
539
561
 
540
562
  def parse_json(json_str):
541
563
  kvpairs = json.loads(json_str)
564
+ damo_record_ver = 0
565
+ if 'damo_reocrd_ver' in kvpairs:
566
+ damo_record_ver = kvpairs['damo_record_ver']
567
+ if damo_record_ver == 1:
568
+ return DamoRecords.from_kvpairs(kvpairs['damo_records'])
542
569
  return [DamonRecord.from_kvpairs(kvp) for kvp in kvpairs]
543
570
 
544
571
  def parse_compressed_json(record_file):
@@ -1913,6 +1940,19 @@ def get_records(tried_regions_of=None, record_file=None,
1913
1940
  filter_copy.filter_records(records)
1914
1941
  return records, None
1915
1942
 
1943
+ def get_damo_records(
1944
+ tried_regions_of=None, record_file=None, snapshot_damos_filters=None,
1945
+ record_filter=None, total_sz_only=False, dont_merge_regions=True):
1946
+ '''
1947
+ Returns DamoRecords and err.
1948
+ '''
1949
+ damon_records, err = get_records(
1950
+ tried_regions_of, record_file, snapshot_damos_filters,
1951
+ record_filter, total_sz_only, dont_merge_regions)
1952
+ if err is not None:
1953
+ return None, err
1954
+ return DamoRecords(kdamonds=[], records=[damon_records]), None
1955
+
1916
1956
  def parse_sort_bytes_ranges_input(bytes_ranges_input):
1917
1957
  try:
1918
1958
  ranges = [[_damo_fmt_str.text_to_bytes(start),
@@ -15,6 +15,50 @@ import _damo_fmt_str
15
15
 
16
16
  # Core data structures
17
17
 
18
+ prep_action_set_pgidle = 'set_pgidle'
19
+
20
+ prep_actions = [
21
+ prep_action_set_pgidle,
22
+ ]
23
+
24
+ class DamonPrep:
25
+ prep_action = None
26
+
27
+ def __init__(self, prep_action=prep_action_set_pgidle):
28
+ if not prep_action in prep_actions:
29
+ raise Exception('wrong prep action (%s)' % prep_action)
30
+
31
+ self.prep_action = prep_action
32
+
33
+ def to_str(self, raw):
34
+ return self.prep_action
35
+
36
+ def __str__(self):
37
+ return self.to_str(False)
38
+
39
+ def __eq__(self, other):
40
+ return type(self) == type(other) and \
41
+ self.prep_action == other.prep_action
42
+
43
+ @classmethod
44
+ def from_kvpairs(cls, kv):
45
+ return DamonPrep(prep_action=kv['prep_action'])
46
+
47
+ def to_kvpairs(self, raw=False):
48
+ return collections.OrderedDict([
49
+ ('prep_action', self.prep_action),
50
+ ])
51
+
52
+ damon_filter_type_anon = 'anon'
53
+ damon_filter_type_memcg = 'memcg'
54
+ damon_filter_type_pgidle_unset = 'pgidle_unset'
55
+
56
+ damon_filter_types = [
57
+ damon_filter_type_anon,
58
+ damon_filter_type_memcg,
59
+ damon_filter_type_pgidle_unset,
60
+ ]
61
+
18
62
  class DamonFilter:
19
63
  filter_type = None # anon, memcg
20
64
  matching = None
@@ -22,6 +66,8 @@ class DamonFilter:
22
66
  path = None
23
67
 
24
68
  def __init__(self, filter_type, matching, allow=False, path=None):
69
+ if not filter_type in damon_filter_types:
70
+ raise Exception('wrong damon filter type (%s)' % filter_type)
25
71
  self.filter_type = filter_type
26
72
  self.matching = _damo_fmt_str.text_to_bool(matching)
27
73
  self.allow = _damo_fmt_str.text_to_bool(allow)
@@ -36,10 +82,9 @@ class DamonFilter:
36
82
  if self.matching is False:
37
83
  words.append('non')
38
84
  words.append(self.filter_type)
39
- if self.filter_type in ['anon']:
40
- return ' '.join(words)
41
85
  if self.filter_type == 'memcg':
42
86
  return ' '.join(words + [self.path])
87
+ return ' '.join(words)
43
88
 
44
89
  def __str__(self):
45
90
  return self.to_str(False)
@@ -67,8 +112,9 @@ class DamonFilter:
67
112
  class DamonProbe:
68
113
  filters = None
69
114
  weight = None
115
+ preps = None
70
116
 
71
- def __init__(self, filters, weight=None):
117
+ def __init__(self, filters, weight=None, preps=None):
72
118
  if type(filters) is not list:
73
119
  raise Exception('filters for DamonProbe() is not a list')
74
120
  self.filters = filters
@@ -77,9 +123,19 @@ class DamonProbe:
77
123
  if type(weight) is not int:
78
124
  raise Exception('weight is not an int')
79
125
  self.weight = weight
126
+ if preps is None:
127
+ preps = []
128
+ if type(preps) is not list:
129
+ raise Exception('preps is not a list')
130
+ self.preps = preps
80
131
 
81
132
  def to_str(self, raw):
82
- words = [', '.join([f.to_str(raw) for f in self.filters])]
133
+ words = []
134
+ if len(self.preps) > 0:
135
+ words.append('prep: %s' % ', '.join([
136
+ prep.to_str(raw) for prep in self.preps]))
137
+ words.append(', filter: ')
138
+ words.append(', '.join([f.to_str(raw) for f in self.filters]))
83
139
  words.append(' (weight: %s)' % self.weight)
84
140
  return ''.join(words)
85
141
 
@@ -89,19 +145,26 @@ class DamonProbe:
89
145
  def __eq__(self, other):
90
146
  return type(self) == type(other) and \
91
147
  self.filters == other.filters and \
92
- self.weight == other.weigt
148
+ self.weight == other.weigt and \
149
+ self.preps == other.preps
93
150
 
94
151
  @classmethod
95
152
  def from_kvpairs(cls, kv):
153
+ if 'preps' in kv:
154
+ preps = [DamonPrep.from_kvpairs(pkv) for pkv in kv['preps']]
155
+ else:
156
+ preps = []
96
157
  return DamonProbe(
97
158
  filters=[
98
159
  DamonFilter.from_kvpairs(filter_kv)
99
160
  for filter_kv in kv['filters']],
100
161
  weight=kv.get('weight', None),
162
+ preps=preps,
101
163
  )
102
164
 
103
165
  def to_kvpairs(self, raw=False):
104
166
  return collections.OrderedDict([
167
+ ('preps', [p.to_kvpairs(raw) for p in self.preps]),
105
168
  ('filters', [f.to_kvpairs(raw) for f in self.filters]),
106
169
  ('weight', self.weight),
107
170
  ])
@@ -752,6 +752,16 @@ def gen_assign_schemes(ctxs, args):
752
752
  scheme_idx += nr
753
753
  return None
754
754
 
755
+ def probe_preps_for(preps_args):
756
+ preps = []
757
+ for prep_action in preps_args:
758
+ try:
759
+ prep = _damon.DamonPrep(prep_action=prep_action)
760
+ except Exception as e:
761
+ return None, 'prep creation fail (%s)' % e
762
+ preps.append(prep)
763
+ return preps, None
764
+
755
765
  def probe_filter_for(filter_arg_fields):
756
766
  fields = filter_arg_fields
757
767
  if len(fields) < 2:
@@ -790,13 +800,25 @@ def probe_filters_for(filters_args):
790
800
  return filters, None
791
801
 
792
802
  def probes_for(args):
803
+ preps, err = probe_preps_for(args.probe_prep)
804
+ if err is not None:
805
+ return None, err
806
+ if args.nr_probe_preps is None:
807
+ args.nr_probe_preps = [len(preps)]
808
+ if sum(args.nr_probe_preps) != len(preps):
809
+ return None, '--nr_probe_preps mismatches --probe_prep (%d != %d)' % (
810
+ sum(args.nr_probe_preps), len(preps))
811
+
793
812
  filters, err = probe_filters_for(args.probe_filter)
794
813
  if err is not None:
795
814
  return None, err
796
- if len(filters) == 0:
815
+
816
+ if len(preps) == 0 and len(filters) == 0:
797
817
  return [], None
818
+
798
819
  probes = []
799
820
  filter_idx = 0
821
+
800
822
  if args.nr_probe_filters is None:
801
823
  args.nr_probe_filters = [len(args.probe_filter)]
802
824
  if sum(args.nr_probe_filters) != len(filters):
@@ -810,11 +832,21 @@ def probes_for(args):
810
832
  % (len(args.probe_weight), len(args.nr_probe_filters))
811
833
  else:
812
834
  args.probe_weight = [0 for _ in args.nr_probe_filters]
813
- for nr in args.nr_probe_filters:
835
+
836
+ nr_probes = len(args.nr_probe_filters)
837
+ for i in range(nr_probes - len(preps)):
838
+ args.nr_probe_preps.append(0)
839
+ prep_idx = 0
840
+
841
+ for probe_idx, nr in enumerate(args.nr_probe_filters):
842
+ preps_for_probe = preps[
843
+ prep_idx:prep_idx + args.nr_probe_preps[probe_idx]]
814
844
  filters_for_probe = filters[filter_idx:filter_idx + nr]
815
845
  weight = args.probe_weight[len(probes)]
816
846
  try:
817
- probe = _damon.DamonProbe(filters=filters_for_probe, weight=weight)
847
+ probe = _damon.DamonProbe(
848
+ preps=preps_for_probe, filters=filters_for_probe,
849
+ weight=weight)
818
850
  except Exception as e:
819
851
  return None, 'probe creation fail (%s)' % e
820
852
  probes.append(probe)
@@ -947,6 +979,21 @@ def deduce_target_update_args(args):
947
979
  print('warning: override --ops by <deducible target> and --regions')
948
980
  args.ops = ['fvaddr']
949
981
 
982
+ def update_args_defaults(args):
983
+ # having default=[] makes complicated global shared states. Instantiate
984
+ # default values here.
985
+ for arg_name in [
986
+ 'probe_prep', 'probe_filter', 'probe_weight', 'damos_action',
987
+ 'damos_sz_region', 'damos_access_rate', 'damos_age',
988
+ 'damos_apply_interval', 'damos_quotas', 'damos_quota_interval',
989
+ 'damos_quota_time', 'damos_quota_space', 'damos_quota_weights',
990
+ 'damos_quota_fail_charge_ratio', 'damos_quota_goal',
991
+ 'damos_quota_goal_tuner', 'damos_nr_quota_goals', 'damos_filter',
992
+ 'damos_nr_filters', 'damos_wmarks', 'damos_max_nr_snapshots',
993
+ ]:
994
+ if getattr(args, arg_name) is None:
995
+ setattr(args, arg_name, [])
996
+
950
997
  def warn_for(arg, feature):
951
998
  if _damo_sysinfo.damon_feature_available(feature):
952
999
  return
@@ -966,6 +1013,17 @@ def warn_unsupported_damon_features_for(args):
966
1013
  if args.sample_primitives is not None:
967
1014
  warn_for('--sample_primitives', 'sysfs/damon_sample_control')
968
1015
 
1016
+ if len(args.probe_prep) > 0:
1017
+ warn_for('--probe_prep', 'sysfs/probe_preps')
1018
+ for probe_filter_args in args.probe_filter:
1019
+ if _damon.damon_filter_type_pgidle_unset in args.probe_filter:
1020
+ warn_for(
1021
+ '--probe_filter of %s' %
1022
+ _damon.damon_filter_type_pgidle_unset,
1023
+ 'sysfs/probe_type_pgidle_unset')
1024
+
1025
+ # mm.git
1026
+
969
1027
  if args.probe_weight != []:
970
1028
  warn_for('--probe_weight', 'sysfs/probe_weights')
971
1029
 
@@ -1158,6 +1216,7 @@ def warn_unsupported_damon_features_for(args):
1158
1216
  ['interface/damon_debugfs', 'interface/damon_sysfs'])
1159
1217
 
1160
1218
  def evaluate_args(args):
1219
+ update_args_defaults(args)
1161
1220
  warn_unsupported_damon_features_for(args)
1162
1221
 
1163
1222
  '''
@@ -1385,8 +1444,16 @@ def set_monitoring_damos_common_args(parser, hide_help=False):
1385
1444
  help='monitoring operations set'
1386
1445
  if not hide_help else argparse.SUPPRESS)
1387
1446
 
1447
+ parser.add_argument('--probe_prep', action='append',
1448
+ metavar='<prep action>',
1449
+ help='data attribute monitoring probe prep'
1450
+ if not hide_help else argparse.SUPPRESS)
1451
+ parser.add_argument('--nr_probe_preps', type=int, nargs='+',
1452
+ metavar='<integer>',
1453
+ help='number of preps for each probe (in order)'
1454
+ if not hide_help else argparse.SUPPRESS)
1455
+
1388
1456
  parser.add_argument('--probe_filter', nargs='+', action='append',
1389
- default=[],
1390
1457
  metavar='<<allow|reject> [non] <type> [option]...>',
1391
1458
  help='data attribute monitoring probe filter'
1392
1459
  if not hide_help else argparse.SUPPRESS)
@@ -1395,7 +1462,7 @@ def set_monitoring_damos_common_args(parser, hide_help=False):
1395
1462
  help='number of filters for each probe (in order)'
1396
1463
  if not hide_help else argparse.SUPPRESS)
1397
1464
  parser.add_argument('--probe_weight', type=int, action='append',
1398
- default=[], metavar='<int>',
1465
+ metavar='<int>',
1399
1466
  help='data attribute probe weight'
1400
1467
  if not hide_help else argparse.SUPPRESS)
1401
1468
  parser.add_argument(
@@ -1456,7 +1523,7 @@ def set_monitoring_argparser(parser, hide_help=False):
1456
1523
 
1457
1524
  def set_damos_argparser(parser, hide_help):
1458
1525
  parser.add_argument('--damos_action', metavar='<action>', nargs='+',
1459
- action='append', default=[],
1526
+ action='append',
1460
1527
  help=' '.join([
1461
1528
  'damos action to apply to the target regions.',
1462
1529
  '<action> should be {%s}.' %
@@ -1467,21 +1534,21 @@ def set_damos_argparser(parser, hide_help):
1467
1534
  'should also be given.'
1468
1535
  ]))
1469
1536
  parser.add_argument('--damos_sz_region', metavar=('<min>', '<max>'),
1470
- nargs=2, default=[], action='append',
1537
+ nargs=2, action='append',
1471
1538
  help='min/max size of damos target regions (bytes)'
1472
1539
  if not hide_help else argparse.SUPPRESS)
1473
1540
  parser.add_argument(
1474
- '--damos_access_rate', metavar=('<min>', '<max>'),
1475
- nargs=2, default=[], action='append',
1541
+ '--damos_access_rate', metavar=('<min>', '<max>'), nargs=2,
1542
+ action='append',
1476
1543
  help='min/max access rate of damos target regions (percent)'
1477
1544
  if not hide_help else argparse.SUPPRESS)
1478
1545
  parser.add_argument(
1479
1546
  '--damos_age', metavar=('<min>', '<max>'), nargs=2,
1480
- default=[], action='append',
1547
+ action='append',
1481
1548
  help='min/max age of damos target regions (microseconds)'
1482
1549
  if not hide_help else argparse.SUPPRESS)
1483
1550
  parser.add_argument('--damos_apply_interval', metavar='<microseconds>',
1484
- action='append', default=[],
1551
+ action='append',
1485
1552
  help='the apply interval for the scheme'
1486
1553
  if not hide_help else argparse.SUPPRESS)
1487
1554
  damos_quotas_help = ' '.join([
@@ -1490,32 +1557,31 @@ def set_damos_argparser(parser, hide_help):
1490
1557
  '[<access rate priority weight> (permil)',
1491
1558
  '[<age priority weight> (permil)]]]]])'])
1492
1559
  parser.add_argument(
1493
- '--damos_quotas', default=[],
1494
- metavar='<quota parameter>', nargs='+', action='append',
1560
+ '--damos_quotas', metavar='<quota parameter>', nargs='+',
1561
+ action='append',
1495
1562
  help=damos_quotas_help if not hide_help else argparse.SUPPRESS)
1496
- parser.add_argument('--damos_quota_interval', default=[],
1497
- metavar='<milliseconds>', action='append',
1563
+ parser.add_argument('--damos_quota_interval', metavar='<milliseconds>',
1564
+ action='append',
1498
1565
  help='quota reset interval'
1499
1566
  if not hide_help else argparse.SUPPRESS)
1500
- parser.add_argument('--damos_quota_time', default=[],
1501
- metavar='<milliseconds>', action='append',
1567
+ parser.add_argument('--damos_quota_time', metavar='<milliseconds>',
1568
+ action='append',
1502
1569
  help='time quota'
1503
1570
  if not hide_help else argparse.SUPPRESS)
1504
- parser.add_argument('--damos_quota_space', default=[], metavar='<bytes>',
1571
+ parser.add_argument('--damos_quota_space', metavar='<bytes>',
1505
1572
  action='append', help='space quota'
1506
1573
  if not hide_help else argparse.SUPPRESS)
1507
- parser.add_argument('--damos_quota_weights', default=[],
1508
- metavar='<permil>', nargs=3, action='append',
1574
+ parser.add_argument('--damos_quota_weights', metavar='<permil>', nargs=3,
1575
+ action='append',
1509
1576
  help='quota\'s prioritization weights'
1510
1577
  if not hide_help else argparse.SUPPRESS)
1511
- parser.add_argument('--damos_quota_fail_charge_ratio', default=[],
1578
+ parser.add_argument('--damos_quota_fail_charge_ratio',
1512
1579
  metavar=('<numerator>', '<denominator>'),
1513
1580
  action='append', nargs=2,
1514
1581
  help='quota failed regions charge ratio'
1515
1582
  if not hide_help else argparse.SUPPRESS)
1516
1583
  parser.add_argument(
1517
1584
  '--damos_quota_goal', nargs='+', action='append',
1518
- default=[],
1519
1585
  metavar='<metric or value>',
1520
1586
  help=' '.join([
1521
1587
  'damos quota goal (<metric> <target value> [optional value]).',
@@ -1523,32 +1589,29 @@ def set_damos_argparser(parser, hide_help):
1523
1589
  ','.join(_damon.qgoal_metrics)])
1524
1590
  if not hide_help else argparse.SUPPRESS)
1525
1591
  parser.add_argument(
1526
- '--damos_quota_goal_tuner', action='append', default=[],
1592
+ '--damos_quota_goal_tuner', action='append',
1527
1593
  help='quota\'s goal-based tuner')
1528
1594
  parser.add_argument(
1529
- '--damos_nr_quota_goals', type=int, nargs='+',
1530
- default=[], metavar='<integer>',
1595
+ '--damos_nr_quota_goals', type=int, nargs='+', metavar='<integer>',
1531
1596
  help='number of quota goals for each scheme (in order)'
1532
1597
  if not hide_help else argparse.SUPPRESS)
1533
1598
  parser.add_argument(
1534
1599
  '--damos_filter', nargs='+', action='append',
1535
- default=[],
1536
1600
  metavar='<<allow|reject> [none] <type> [option]...>',
1537
1601
  help='damos filter' if not hide_help else argparse.SUPPRESS)
1538
1602
  parser.add_argument(
1539
- '--damos_nr_filters', type=int, nargs='+', default=[],
1540
- metavar='<integer>',
1603
+ '--damos_nr_filters', type=int, nargs='+', metavar='<integer>',
1541
1604
  help='number of filters for each scheme (in order)'
1542
1605
  if not hide_help else argparse.SUPPRESS)
1543
1606
  parser.add_argument(
1544
- '--damos_wmarks', nargs=5, action='append', default=[],
1607
+ '--damos_wmarks', nargs=5, action='append',
1545
1608
  metavar=('<metric (none|free_mem_rate)>', '<interval (us)>',
1546
1609
  '<high mark (permil)>', '<mid mark (permil)>',
1547
1610
  '<low mark (permil)>'),
1548
1611
  help='damos watermarks'
1549
1612
  if not hide_help else argparse.SUPPRESS)
1550
1613
  parser.add_argument(
1551
- '--damos_max_nr_snapshots', action='append', default=[],
1614
+ '--damos_max_nr_snapshots', action='append',
1552
1615
  help='damos max_nr_snapshots')
1553
1616
  parser.add_argument('--nr_schemes', metavar='<number>', nargs='+', type=int,
1554
1617
  help='number of schemes for each context (in order)'
@@ -348,11 +348,27 @@ features_list = [
348
348
  DamonFeature(name='sysfs/attrs_monitoring',
349
349
  upstream_status='merged in v7.2-rc1 (45c49d9fd6089)',
350
350
  upstreamed_version='7.2'),
351
+ DamonFeature(name='sysfs/probe_type_anon',
352
+ upstream_status='merged in v7.2-rc1 (8caba1448278)',
353
+ upstreamed_version='7.2'),
354
+ DamonFeature(name='sysfs/probe_type_memcg',
355
+ upstream_status='merged in v7.2-rc1 (c71f8e13462d)',
356
+ upstreamed_version='7.2'),
351
357
  DamonFeature(name='trace/damon_region_aggregated',
352
358
  upstream_status='merged in v7.2-rc1 (45c49d9fd6089)',
353
359
  upstreamed_version='7.2'),
354
360
 
355
361
  DamonFeature(name='sysfs/probe_weights',
362
+ upstream_status='merged into mm.git',
363
+ upstreamed_version='none'),
364
+
365
+ DamonFeature(name='sysfs/probe_preps',
366
+ upstream_status='hacking on damon/next',
367
+ upstreamed_version='none'),
368
+ DamonFeature(name='sysfs/probe_prep_set_pgidle',
369
+ upstream_status='hacking on damon/next',
370
+ upstreamed_version='none'),
371
+ DamonFeature(name='sysfs/probe_type_pgidle_unset',
356
372
  upstream_status='hacking on damon/next',
357
373
  upstreamed_version='none'),
358
374
 
@@ -570,6 +570,24 @@ def write_ops_attrs_dir(dir_path, ops_attrs):
570
570
  if err is not None:
571
571
  return err
572
572
 
573
+ def write_probe_prep_dir(dir_path, prep):
574
+ err = _damo_fs.write_file(
575
+ os.path.join(dir_path, 'prep_action'), prep.prep_action)
576
+ if err is not None:
577
+ return err
578
+ return None
579
+
580
+ def write_probe_preps_dir(dir_path, preps):
581
+ err = ensure_nr_file_for(os.path.join(dir_path, 'nr_preps'), preps)
582
+ if err is not None:
583
+ return err
584
+
585
+ for idx, prep in enumerate(preps):
586
+ err = write_probe_prep_dir(os.path.join(dir_path, '%d' % idx), prep)
587
+ if err is not None:
588
+ return err
589
+ return None
590
+
573
591
  def write_probe_filter_dir(dir_path, filter):
574
592
  err = _damo_fs.write_file(
575
593
  os.path.join(dir_path, 'type'), filter.filter_type)
@@ -590,6 +608,12 @@ def write_probe_filter_dir(dir_path, filter):
590
608
  return None
591
609
 
592
610
  def write_probe_dir(dir_path, probe):
611
+ preps_dir = os.path.join(dir_path, 'preps')
612
+ if os.path.isdir(preps_dir):
613
+ err = write_probe_preps_dir(preps_dir, probe.preps)
614
+ if err is not None:
615
+ return err
616
+
593
617
  filters_dir = os.path.join(dir_path, 'filters')
594
618
  err = ensure_nr_file_for(os.path.join(filters_dir, 'nr_filters'),
595
619
  probe.filters)
@@ -1056,16 +1080,27 @@ def files_content_to_target(files_content):
1056
1080
  regions = files_content_to_regions(files_content['regions'])
1057
1081
  return _damon.DamonTarget(pid, regions, obsolete=obsolete)
1058
1082
 
1083
+ def files_content_to_probe_preps(files_content):
1084
+ preps = []
1085
+ for kv in number_sorted_dirs(files_content):
1086
+ preps.append(_damon.DamonPrep(prep_action=kv['prep_action'].strip()))
1087
+ return preps
1088
+
1059
1089
  def files_content_to_damon_filter(files_content):
1060
1090
  path = None
1061
1091
  if 'path' in files_content:
1062
- files_content.get('path').strip()
1092
+ path = files_content['path'].strip()
1063
1093
  return _damon.DamonFilter(
1064
1094
  filter_type=files_content['type'].strip(),
1065
1095
  matching=files_content['matching'].strip(),
1066
1096
  allow=files_content['allow'].strip(), path=path)
1067
1097
 
1068
1098
  def files_content_to_probe(files_content):
1099
+ if 'preps' in files_content:
1100
+ preps = files_content_to_probe_preps(files_content['preps'])
1101
+ else:
1102
+ preps = []
1103
+
1069
1104
  filters_content = files_content['filters']
1070
1105
  filters = []
1071
1106
  for kv in number_sorted_dirs(filters_content):
@@ -1075,7 +1110,7 @@ def files_content_to_probe(files_content):
1075
1110
  weight = int(files_content['weight'])
1076
1111
  else:
1077
1112
  weight = None
1078
- return _damon.DamonProbe(filters=filters, weight=weight)
1113
+ return _damon.DamonProbe(preps=preps, filters=filters, weight=weight)
1079
1114
 
1080
1115
  def files_content_to_probes(files_content):
1081
1116
  probes = []
@@ -1450,6 +1485,8 @@ def mk_feature_supports_map():
1450
1485
  if os.path.isdir(
1451
1486
  os.path.join(ctx_dir_of(0, 0), 'monitoring_attrs', 'probes')):
1452
1487
  supports_map['sysfs/attrs_monitoring'] = True
1488
+ supports_map['sysfs/probe_type_anon'] = True
1489
+ supports_map['sysfs/probe_type_memcg'] = True
1453
1490
 
1454
1491
 
1455
1492
  if supports_map['sysfs/attrs_monitoring'] is True:
@@ -1473,6 +1510,11 @@ def mk_feature_supports_map():
1473
1510
  if os.path.isfile(os.path.join(probe_dir, 'weight')):
1474
1511
  supports_map['sysfs/probe_weights'] = True
1475
1512
 
1513
+ if os.path.isdir(os.path.join(probe_dir, 'preps')):
1514
+ supports_map['sysfs/probe_preps'] = True
1515
+ supports_map['sysfs/probe_prep_set_pgidle'] = True
1516
+ supports_map['sysfs/probe_type_pgidle_unset'] = True
1517
+
1476
1518
  if os.path.isdir(os.path.join(ctx_dir_of(0, 0), 'operations_attrs')):
1477
1519
  supports_map['sysfs/ops_attrs'] = True
1478
1520
 
@@ -339,15 +339,14 @@ def max_access_hz(intervals):
339
339
 
340
340
  def snapshot_intervals_str(snapshot, record, fmt):
341
341
  intervals = record.intervals
342
- aggr_sample_ratio = intervals.aggr / intervals.sample
342
+ aggr_sample_ratio = intervals.aggr // intervals.sample
343
343
  snapshot_aggr_us = infer_aggr_time_us(snapshot, record)
344
344
  snapshot_sample_us = snapshot_aggr_us / aggr_sample_ratio
345
- max_access_hz = aggr_sample_ratio / (snapshot_aggr_us / 1000000)
346
345
 
347
- return 'sample %s aggr %s (max access hz %s)' % (
346
+ return 'sample %s aggr %s (max probe hits %s)' % (
348
347
  _damo_fmt_str.format_time_us(snapshot_sample_us, fmt.raw_number),
349
348
  _damo_fmt_str.format_time_us(snapshot_aggr_us, fmt.raw_number),
350
- _damo_fmt_str.format_hz(max_access_hz, fmt.raw_number, no_suffix=True))
349
+ _damo_fmt_str.format_nr(aggr_sample_ratio, fmt.raw_number))
351
350
 
352
351
  def estimated_mem_bw(snapshot, record, fmt, filter_passed_only=False):
353
352
  access_bytes = 0
@@ -768,95 +767,6 @@ def df_passed_heatmap_str(snapshot, record, fmt):
768
767
  total_bytes=None),
769
768
  record, fmt)
770
769
 
771
- def rescale(val, orig_scale_minmax, new_scale_minmax, logscale=True):
772
- '''Return a value in new scale
773
-
774
- Parameters
775
- ----------
776
- val : int, float
777
- The value to rescale
778
- orig_scale_minmax : list
779
- min/max values of original scale
780
- new_scale_minmax : list
781
- min/max values of new scale
782
- logscale : bool
783
- whether to use logscale (True) or linearscale (False)
784
-
785
- Returns
786
- -------
787
- float
788
- The rescaled value
789
- '''
790
-
791
- if logscale:
792
- log_val = math.log(val, 2) if val > 0 else 0
793
- log_minmax = [math.log(v, 2) if v > 0 else 0
794
- for v in orig_scale_minmax]
795
- val = log_val
796
- orig_scale_minmax = log_minmax
797
- orig_length = orig_scale_minmax[1] - orig_scale_minmax[0]
798
- new_length = new_scale_minmax[1] - new_scale_minmax[0]
799
- ratio = new_length / orig_length if orig_length > 0 else 1
800
- return (val - orig_scale_minmax[0]) * ratio + new_scale_minmax[0]
801
-
802
- class BoxValue:
803
- val = None
804
- val_min_max = None # list of min/max
805
- display_min_max = None # list of min/max
806
- display_logscale = None # bool
807
-
808
- def __init__(self, val, val_min_max, display_min_max, display_logscale):
809
- self.val = val
810
- self.val_min_max = val_min_max
811
- self.display_min_max = display_min_max
812
- self.display_logscale = display_logscale
813
-
814
- def display_value(self):
815
- return rescale(self.val, self.val_min_max, self.display_min_max,
816
- self.display_logscale)
817
-
818
- class ColoredBox:
819
- # BoxValue
820
- length = None
821
- color = None
822
- height = None
823
-
824
- colorset = None
825
- horizontal_align = None
826
-
827
- def __init__(self, length, horizontal_align, color, colorset, height):
828
- self.length = length
829
- self.color = color
830
- self.horizontal_align = horizontal_align
831
- self.colorset = colorset
832
- self.height = height
833
-
834
- def __str__(self):
835
- length = int(self.length.display_value())
836
-
837
- if self.height.val != None:
838
- height = int(self.height.display_value())
839
- else:
840
- self.height.display_min, self.height.display_max = [1, 1]
841
- height = 1
842
-
843
- if type(self.color.val) == str:
844
- row = '%s' % (self.color.val * length)
845
- else:
846
- color_level = int(self.color.display_value())
847
- row = '%s' % _damo_ascii_color.colored(
848
- ('%d' % color_level) * length, self.colorset, color_level)
849
- row = '|%s|' % row
850
-
851
- if self.horizontal_align == 'right':
852
- indent = ' ' * (self.length.display_min_max[1] - length)
853
- row = indent + row
854
-
855
- box = '\n'.join([row] * height)
856
- if self.height.display_min_max[1] > 1:
857
- box += '\n'
858
- return box
859
-
860
770
  def apply_min_chars(min_chars, field_name, txt):
861
771
  # min_chars: [[<field name>, <number of min chars>]...]
862
772
  for name, nr in min_chars:
@@ -3,7 +3,7 @@
3
3
  import os
4
4
  import subprocess
5
5
 
6
- __version__ = '3.3.2'
6
+ __version__ = '3.3.4'
7
7
 
8
8
  def get_release_version():
9
9
  return __version__
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: damo
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: DAMON user-space tool
5
5
  Home-page: https://github.com/damonitor/damo
6
6
  Author: SeongJae Park
@@ -71,7 +71,7 @@ The second and last commands will show the access pattern of your workload,
71
71
  like below:
72
72
 
73
73
  ![masim_stairs_snapshot](images/masim_stairs_snapshot.png)
74
- ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.2/images/masim_stairs_heatmap_ascii.png)
74
+ ![masim stairs heatmap in ascii](https://raw.githubusercontent.com/damonitor/damo/v3.3.4/images/masim_stairs_heatmap_ascii.png)
75
75
 
76
76
 
77
77
  FAQs
@@ -90,7 +90,7 @@ Where can I get more detailed usage?
90
90
  ------------------------------------
91
91
 
92
92
  The below sections provide quick introductions for `damo`'s major features.
93
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
93
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
94
94
 
95
95
 
96
96
  What does the version numbers mean?
@@ -115,7 +115,7 @@ We try our best to make `damo` stable and doesn't introduce regressions to
115
115
  users. However, nothing goes forever. Sometimes, some features will be
116
116
  deprecated. Some features will have longer support more than others.
117
117
 
118
- In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) and not explicitly
118
+ In short, features that documented on [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) and not explicitly
119
119
  marked as experimental will be better supported, and provides at least three
120
120
  months of deprecation grace period. Within the grace period, users can ask
121
121
  extension of the support. Even after the grace period, please reach out to
@@ -138,7 +138,7 @@ Quick Intro for Major Features
138
138
  ==============================
139
139
 
140
140
  Below are quick introductions for `damo`'s major features.
141
- For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.2/USAGE.md) file.
141
+ For more detailed usage, please refer to [USAGE.md](https://github.com/damonitor/damo/blob/v3.3.4/USAGE.md) file.
142
142
 
143
143
 
144
144
  Snapshot Data Access Pattern
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes