brintos

brintos / linux-shallow public Read only

0
0
Text · 17.6 KiB · 6e136dc Raw
544 lines · python
1# SPDX-License-Identifier: GPL-2.02 3import os4 5ksft_skip=46 7sysfs_root = None8with open('/proc/mounts', 'r') as f:9    for line in f:10        dev_name, mount_point, dev_fs = line.split()[:3]11        if dev_fs == 'sysfs':12            sysfs_root = '%s/kernel/mm/damon/admin' % mount_point13            break14if sysfs_root is None:15    print('Seems sysfs not mounted?')16    exit(ksft_skip)17 18def write_file(path, string):19    "Returns error string if failed, or None otherwise"20    string = '%s' % string21    try:22        with open(path, 'w') as f:23            f.write(string)24    except Exception as e:25        return '%s' % e26    return None27 28def read_file(path):29    '''Returns the read content and error string.  The read content is None if30    the reading failed'''31    try:32        with open(path, 'r') as f:33            return f.read(), None34    except Exception as e:35        return None, '%s' % e36 37class DamosAccessPattern:38    size = None39    nr_accesses = None40    age = None41    scheme = None42 43    def __init__(self, size=None, nr_accesses=None, age=None):44        self.size = size45        self.nr_accesses = nr_accesses46        self.age = age47 48        if self.size is None:49            self.size = [0, 2**64 - 1]50        if self.nr_accesses is None:51            self.nr_accesses = [0, 2**64 - 1]52        if self.age is None:53            self.age = [0, 2**64 - 1]54 55    def sysfs_dir(self):56        return os.path.join(self.scheme.sysfs_dir(), 'access_pattern')57 58    def stage(self):59        err = write_file(60                os.path.join(self.sysfs_dir(), 'sz', 'min'), self.size[0])61        if err is not None:62            return err63        err = write_file(64                os.path.join(self.sysfs_dir(), 'sz', 'max'), self.size[1])65        if err is not None:66            return err67        err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'min'),68                self.nr_accesses[0])69        if err is not None:70            return err71        err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'max'),72                self.nr_accesses[1])73        if err is not None:74            return err75        err = write_file(76                os.path.join(self.sysfs_dir(), 'age', 'min'), self.age[0])77        if err is not None:78            return err79        err = write_file(80                os.path.join(self.sysfs_dir(), 'age', 'max'), self.age[1])81        if err is not None:82            return err83 84qgoal_metric_user_input = 'user_input'85qgoal_metric_some_mem_psi_us = 'some_mem_psi_us'86qgoal_metrics = [qgoal_metric_user_input, qgoal_metric_some_mem_psi_us]87 88class DamosQuotaGoal:89    metric = None90    target_value = None91    current_value = None92    effective_bytes = None93    quota = None            # owner quota94    idx = None95 96    def __init__(self, metric, target_value=10000, current_value=0):97        self.metric = metric98        self.target_value = target_value99        self.current_value = current_value100 101    def sysfs_dir(self):102        return os.path.join(self.quota.sysfs_dir(), 'goals', '%d' % self.idx)103 104    def stage(self):105        err = write_file(os.path.join(self.sysfs_dir(), 'target_metric'),106                         self.metric)107        if err is not None:108            return err109        err = write_file(os.path.join(self.sysfs_dir(), 'target_value'),110                         self.target_value)111        if err is not None:112            return err113        err = write_file(os.path.join(self.sysfs_dir(), 'current_value'),114                         self.current_value)115        if err is not None:116            return err117        return None118 119class DamosQuota:120    sz = None                   # size quota, in bytes121    ms = None                   # time quota122    goals = None                # quota goals123    reset_interval_ms = None    # quota reset interval124    scheme = None               # owner scheme125 126    def __init__(self, sz=0, ms=0, goals=None, reset_interval_ms=0):127        self.sz = sz128        self.ms = ms129        self.reset_interval_ms = reset_interval_ms130        self.goals = goals if goals is not None else []131        for idx, goal in enumerate(self.goals):132            goal.idx = idx133            goal.quota = self134 135    def sysfs_dir(self):136        return os.path.join(self.scheme.sysfs_dir(), 'quotas')137 138    def stage(self):139        err = write_file(os.path.join(self.sysfs_dir(), 'bytes'), self.sz)140        if err is not None:141            return err142        err = write_file(os.path.join(self.sysfs_dir(), 'ms'), self.ms)143        if err is not None:144            return err145        err = write_file(os.path.join(self.sysfs_dir(), 'reset_interval_ms'),146                         self.reset_interval_ms)147        if err is not None:148            return err149 150        nr_goals_file = os.path.join(self.sysfs_dir(), 'goals', 'nr_goals')151        content, err = read_file(nr_goals_file)152        if err is not None:153            return err154        if int(content) != len(self.goals):155            err = write_file(nr_goals_file, len(self.goals))156            if err is not None:157                return err158        for goal in self.goals:159            err = goal.stage()160            if err is not None:161                return err162        return None163 164class DamosStats:165    nr_tried = None166    sz_tried = None167    nr_applied = None168    sz_applied = None169    qt_exceeds = None170 171    def __init__(self, nr_tried, sz_tried, nr_applied, sz_applied, qt_exceeds):172        self.nr_tried = nr_tried173        self.sz_tried = sz_tried174        self.nr_applied = nr_applied175        self.sz_applied = sz_applied176        self.qt_exceeds = qt_exceeds177 178class DamosTriedRegion:179    def __init__(self, start, end, nr_accesses, age):180        self.start = start181        self.end = end182        self.nr_accesses = nr_accesses183        self.age = age184 185class Damos:186    action = None187    access_pattern = None188    quota = None189    apply_interval_us = None190    # todo: Support watermarks, stats191    idx = None192    context = None193    tried_bytes = None194    stats = None195    tried_regions = None196 197    def __init__(self, action='stat', access_pattern=DamosAccessPattern(),198                 quota=DamosQuota(), apply_interval_us=0):199        self.action = action200        self.access_pattern = access_pattern201        self.access_pattern.scheme = self202        self.quota = quota203        self.quota.scheme = self204        self.apply_interval_us = apply_interval_us205 206    def sysfs_dir(self):207        return os.path.join(208                self.context.sysfs_dir(), 'schemes', '%d' % self.idx)209 210    def stage(self):211        err = write_file(os.path.join(self.sysfs_dir(), 'action'), self.action)212        if err is not None:213            return err214        err = self.access_pattern.stage()215        if err is not None:216            return err217        err = write_file(os.path.join(self.sysfs_dir(), 'apply_interval_us'),218                         '%d' % self.apply_interval_us)219        if err is not None:220            return err221 222        err = self.quota.stage()223        if err is not None:224            return err225 226        # disable watermarks227        err = write_file(228                os.path.join(self.sysfs_dir(), 'watermarks', 'metric'), 'none')229        if err is not None:230            return err231 232        # disable filters233        err = write_file(234                os.path.join(self.sysfs_dir(), 'filters', 'nr_filters'), '0')235        if err is not None:236            return err237 238class DamonTarget:239    pid = None240    # todo: Support target regions if test is made241    idx = None242    context = None243 244    def __init__(self, pid):245        self.pid = pid246 247    def sysfs_dir(self):248        return os.path.join(249                self.context.sysfs_dir(), 'targets', '%d' % self.idx)250 251    def stage(self):252        err = write_file(253                os.path.join(self.sysfs_dir(), 'regions', 'nr_regions'), '0')254        if err is not None:255            return err256        return write_file(257                os.path.join(self.sysfs_dir(), 'pid_target'), self.pid)258 259class DamonAttrs:260    sample_us = None261    aggr_us = None262    update_us = None263    min_nr_regions = None264    max_nr_regions = None265    context = None266 267    def __init__(self, sample_us=5000, aggr_us=100000, update_us=1000000,268            min_nr_regions=10, max_nr_regions=1000):269        self.sample_us = sample_us270        self.aggr_us = aggr_us271        self.update_us = update_us272        self.min_nr_regions = min_nr_regions273        self.max_nr_regions = max_nr_regions274 275    def interval_sysfs_dir(self):276        return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',277                'intervals')278 279    def nr_regions_range_sysfs_dir(self):280        return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',281                'nr_regions')282 283    def stage(self):284        err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'),285                self.sample_us)286        if err is not None:287            return err288        err = write_file(os.path.join(self.interval_sysfs_dir(), 'aggr_us'),289                self.aggr_us)290        if err is not None:291            return err292        err = write_file(os.path.join(self.interval_sysfs_dir(), 'update_us'),293                self.update_us)294        if err is not None:295            return err296 297        err = write_file(298                os.path.join(self.nr_regions_range_sysfs_dir(), 'min'),299                self.min_nr_regions)300        if err is not None:301            return err302 303        err = write_file(304                os.path.join(self.nr_regions_range_sysfs_dir(), 'max'),305                self.max_nr_regions)306        if err is not None:307            return err308 309class DamonCtx:310    ops = None311    monitoring_attrs = None312    targets = None313    schemes = None314    kdamond = None315    idx = None316 317    def __init__(self, ops='paddr', monitoring_attrs=DamonAttrs(), targets=[],318            schemes=[]):319        self.ops = ops320        self.monitoring_attrs = monitoring_attrs321        self.monitoring_attrs.context = self322 323        self.targets = targets324        for idx, target in enumerate(self.targets):325            target.idx = idx326            target.context = self327 328        self.schemes = schemes329        for idx, scheme in enumerate(self.schemes):330            scheme.idx = idx331            scheme.context = self332 333    def sysfs_dir(self):334        return os.path.join(self.kdamond.sysfs_dir(), 'contexts',335                '%d' % self.idx)336 337    def stage(self):338        err = write_file(339                os.path.join(self.sysfs_dir(), 'operations'), self.ops)340        if err is not None:341            return err342        err = self.monitoring_attrs.stage()343        if err is not None:344            return err345 346        nr_targets_file = os.path.join(347                self.sysfs_dir(), 'targets', 'nr_targets')348        content, err = read_file(nr_targets_file)349        if err is not None:350            return err351        if int(content) != len(self.targets):352            err = write_file(nr_targets_file, '%d' % len(self.targets))353            if err is not None:354                return err355        for target in self.targets:356            err = target.stage()357            if err is not None:358                return err359 360        nr_schemes_file = os.path.join(361                self.sysfs_dir(), 'schemes', 'nr_schemes')362        content, err = read_file(nr_schemes_file)363        if err is not None:364            return err365        if int(content) != len(self.schemes):366            err = write_file(nr_schemes_file, '%d' % len(self.schemes))367            if err is not None:368                return err369        for scheme in self.schemes:370            err = scheme.stage()371            if err is not None:372                return err373        return None374 375class Kdamond:376    state = None377    pid = None378    contexts = None379    idx = None      # index of this kdamond between siblings380    kdamonds = None # parent381 382    def __init__(self, contexts=[]):383        self.contexts = contexts384        for idx, context in enumerate(self.contexts):385            context.idx = idx386            context.kdamond = self387 388    def sysfs_dir(self):389        return os.path.join(self.kdamonds.sysfs_dir(), '%d' % self.idx)390 391    def start(self):392        nr_contexts_file = os.path.join(self.sysfs_dir(),393                'contexts', 'nr_contexts')394        content, err = read_file(nr_contexts_file)395        if err is not None:396            return err397        if int(content) != len(self.contexts):398            err = write_file(nr_contexts_file, '%d' % len(self.contexts))399            if err is not None:400                return err401 402        for context in self.contexts:403            err = context.stage()404            if err is not None:405                return err406        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'on')407        return err408 409    def stop(self):410        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'off')411        return err412 413    def update_schemes_tried_regions(self):414        err = write_file(os.path.join(self.sysfs_dir(), 'state'),415                         'update_schemes_tried_regions')416        if err is not None:417            return err418        for context in self.contexts:419            for scheme in context.schemes:420                tried_regions = []421                tried_regions_dir = os.path.join(422                        scheme.sysfs_dir(), 'tried_regions')423                for filename in os.listdir(424                        os.path.join(scheme.sysfs_dir(), 'tried_regions')):425                    tried_region_dir = os.path.join(tried_regions_dir, filename)426                    if not os.path.isdir(tried_region_dir):427                        continue428                    region_values = []429                    for f in ['start', 'end', 'nr_accesses', 'age']:430                        content, err = read_file(431                                os.path.join(tried_region_dir, f))432                        if err is not None:433                            return err434                        region_values.append(int(content))435                    tried_regions.append(DamosTriedRegion(*region_values))436                scheme.tried_regions = tried_regions437 438    def update_schemes_tried_bytes(self):439        err = write_file(os.path.join(self.sysfs_dir(), 'state'),440                'update_schemes_tried_bytes')441        if err is not None:442            return err443        for context in self.contexts:444            for scheme in context.schemes:445                content, err = read_file(os.path.join(scheme.sysfs_dir(),446                    'tried_regions', 'total_bytes'))447                if err is not None:448                    return err449                scheme.tried_bytes = int(content)450 451    def update_schemes_stats(self):452        err = write_file(os.path.join(self.sysfs_dir(), 'state'),453                'update_schemes_stats')454        if err is not None:455            return err456        for context in self.contexts:457            for scheme in context.schemes:458                stat_values = []459                for stat in ['nr_tried', 'sz_tried', 'nr_applied',460                             'sz_applied', 'qt_exceeds']:461                    content, err = read_file(462                            os.path.join(scheme.sysfs_dir(), 'stats', stat))463                    if err is not None:464                        return err465                    stat_values.append(int(content))466                scheme.stats = DamosStats(*stat_values)467 468    def update_schemes_effective_quotas(self):469        err = write_file(os.path.join(self.sysfs_dir(), 'state'),470                         'update_schemes_effective_quotas')471        if err is not None:472            return err473        for context in self.contexts:474            for scheme in context.schemes:475                for goal in scheme.quota.goals:476                    content, err = read_file(477                            os.path.join(scheme.quota.sysfs_dir(),478                                         'effective_bytes'))479                    if err is not None:480                        return err481                    goal.effective_bytes = int(content)482        return None483 484    def commit(self):485        nr_contexts_file = os.path.join(self.sysfs_dir(),486                'contexts', 'nr_contexts')487        content, err = read_file(nr_contexts_file)488        if err is not None:489            return err490        if int(content) != len(self.contexts):491            err = write_file(nr_contexts_file, '%d' % len(self.contexts))492            if err is not None:493                return err494 495        for context in self.contexts:496            err = context.stage()497            if err is not None:498                return err499        err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'commit')500        return err501 502 503    def commit_schemes_quota_goals(self):504        for context in self.contexts:505            for scheme in context.schemes:506                for goal in scheme.quota.goals:507                    err = goal.stage()508                    if err is not None:509                        print('commit_schemes_quota_goals failed stagign: %s'%510                              err)511                        exit(1)512        return write_file(os.path.join(self.sysfs_dir(), 'state'),513                         'commit_schemes_quota_goals')514 515class Kdamonds:516    kdamonds = []517 518    def __init__(self, kdamonds=[]):519        self.kdamonds = kdamonds520        for idx, kdamond in enumerate(self.kdamonds):521            kdamond.idx = idx522            kdamond.kdamonds = self523 524    def sysfs_dir(self):525        return os.path.join(sysfs_root, 'kdamonds')526 527    def start(self):528        err = write_file(os.path.join(self.sysfs_dir(),  'nr_kdamonds'),529                '%s' % len(self.kdamonds))530        if err is not None:531            return err532        for kdamond in self.kdamonds:533            err = kdamond.start()534            if err is not None:535                return err536        return None537 538    def stop(self):539        for kdamond in self.kdamonds:540            err = kdamond.stop()541            if err is not None:542                return err543        return None544