OS实验—LRU四种算法 python实现

项目代码下载: github
(程序实现方法参考于 @Tony Poerio)

如有任何问题,欢迎提出指正~

一、LRU的计数器实现(counter implementation)

原理:为page table 中的每一个entry都添加一个“时间域” , 然后CPU添加一个时钟或者计数器。一个page每次被引用,时钟或计数器的值就会被 copy 到此 page 所在 entry 的“ 时间域 ”内,发生 page fault 时就将时间最小或者计数值最小的被替换。

    def add_or_update_successful(self, vpn, read_or_write):
        # first check if we have a hit
        for elem in self.frame_list:
            if elem.VPN == vpn:
                # mark that we had a hit
                self.hit = True
                self.CPUcounter += 1    # 全局的CPU计时器每次操作+1
               
                elem.in_use = True
                elem.VPN = vpn
                # if we're doing a write, need to set dirty bit
                if read_or_write == 'W':
                    elem.dirty = True
                # selected VPN was accessed
                else:
                    elem.pcount = self.CPUcounter
                   # 把页面加入帧数组之中,并将其计数器更新为最新
                # and return
                return True

        else:
            self.hit = False
            # try and add to an empty space, even though we have a page fault
            if not self.add_after_page_fault(vpn, read_or_write):
                # and if that returns false, we need to EVICT and try again
                self.evict = True 
                self.evict_page()
            	return False
             else:
                return True

    def add_after_page_fault(self, vpn, read_or_write):
        for elem in self.frame_list:
            if not elem.in_use:
                elem.in_use = True
                elem.VPN = vpn
                # if we're doing a write, need to set dirty bit
                if read_or_write == 'W':
                    elem.dirty = True
                else:
                    # if we have a read, mark our reference
                    # 并将其计数器更新为最新
                    elem.pcount = self.CPUcounter
                # and return
                return True

        # if we make it this far, then all items are in use, so return false
        return False

    def evict_page(self):
        lowest_value = self.CPUcounter
        lowest_value_vpn = 0
        lowest_value_ppn = 0

        for elem in self.frame_list:
            # index by the key to get a value
            # value = elem.last_reference
            value = elem.pcount             # 选出计时器最小的作为替换页
            # find the lowest value overall, and get its PPN and VPN
            if value < lowest_value:
                lowest_value = value
                lowest_value_vpn = elem.VPN
                lowest_value_ppn = elem.PPN

        # remove the loest value vpn
        self.remove(lowest_value_ppn, lowest_value_vpn)
二、LRU的栈实现(stack implementation)

原理:采用栈的方式,栈的实现可以用指针链表。每当引用一个page,该 page 就从栈中删除,然后重新放到栈顶,这样栈底部的 page 就是最久未使用的,将作为替换页。

我们运用 frame_list 模拟栈的实现,0元素为栈底

    def inPPN(self):   # 排序编号,方便索引被击中的元素
        # initalize our PPNs           # 但是多次调用这个函数,好像增加了时间,失去了一定效率
        counter = 0             
        for elem in self.frame_list:
            elem.PPN = counter
            counter += 1

    def add_or_update_successful(self, vpn, read_or_write):
        # first check if we have a hit
        for elem in self.frame_list:
            if elem.VPN == vpn:
                # mark that we had a hit
                self.hit = True
                # add the page
                # set values accordingly
                elem.in_use = True
                elem.VPN = vpn     
                # 这里尊重原作者的想法把write,read区别对待,虽然我觉得write也属于最近访问
                # if we're doing a write, need to set dirty bit
                if read_or_write == 'W':
                    elem.dirty = True
                # if we have a READ
                # selected VPN was accessed
                else:                      #被访问,则从栈底移到栈顶
                    self.frame_list.pop(elem.PPN)
                    self.frame_list.append(elem)
                    self.inPPN()

                # and return
                return True

        else:
            self.hit = False
            # try and add to an empty space, even though we have a page fault
            if not self.add_after_page_fault(vpn, read_or_write):
                # and if that returns false, we need to EVICT and try again
                self.evict = True
                # if the page is dirty, we need to do a disk write
                if self.frame_list[0].dirty:
                    self.dirty = True
                self.frame_list.pop(0)    # 如果替换就移除栈底元素
                self.numframe -= 1
            	return False
            else:
                return True


    def add_after_page_fault(self, vpn, read_or_write):
        if self.numframe < self.PAGE_TABLE.num_frames:  # 帧满了
            newframe = pg.Frame()
            newframe.dirty = False
            newframe.in_use = False
            self.frame_list.append(newframe)
            self.inPPN()
            newframe.in_use = True
            newframe.VPN = vpn
            self.numframe += 1
            if read_or_write == 'W':
                newframe.dirty = True

                # and return
            return True

        # if we make it this far, then all items are in use, so return false
        elif self.numframe >= self.PAGE_TABLE.num_frames:
            return False
        
三、Additional-Reference-Bits Algorithm
  • Keep an 8-bit bytes for each page in main memory.
  • At regular intervals, shifts the bits right 1 bit, shift the reference bit into the lower-order bit.
  • Interpret these 8-bit bytes as unsigned integers, the page with lowest number is the LRU page.

给每个frame设置reference bit:

# 在 frame类中添加如下代码
# reference bit 的实现类似于移位寄存器, 8 bit, for ARB
        bit_string = '{:0%db}' % 8
        self.reference = bit_string.format(128)  # initialize as '10000000'

每一次的移位算法:

但只是逻辑,最好在代码里添加

    def shift(self, vpn):
        # left_shift
        for elem in self.frame_list:
            if elem.in_use == True:
                temp = elem.reference[:-1]
                if elem.VPN == vpn:
                    elem.reference = '1' + temp
                else:
                    elem.reference = '0' + temp

选出要替换的页:

    def evict_page(self):
        lowest_value = 128
        lowest_value_vpn = 0
        lowest_value_ppn = 0

        for elem in self.frame_list:
            # index by the key to get a value
            value = int(elem.reference, 2)     # 越最近使用的'1'在最高位,其数值越大
            if value < lowest_value:           # 所以选择出数值最小的页移除
                lowest_value = value
                lowest_value_vpn = elem.VPN
                lowest_value_ppn = elem.PPN

        # remove the lowest value vpn
        self.remove(lowest_value_ppn, lowest_value_vpn)

主要实现:

    def add_or_update_successful(self, vpn, read_or_write):
        # first check if we have a hit
        for elem in self.frame_list:
            temp = elem.reference[:-1]
            if elem.VPN == vpn:
                elem.reference = '1' + temp
                # mark that we had a hit
                self.hit = True
                # add the page
                # set values accordingly
                elem.in_use = True
                elem.VPN = vpn
                # if we're doing a write, need to set dirty bit
                if read_or_write == 'W':
                    elem.dirty = True
                # if we have a READ
                # selected VPN was accessed
                return True
            else:
                elem.reference = '0' + temp

        self.hit = False
        # try and add to an empty space, even though we have a page fault
        if not self.add_after_page_fault(vpn, read_or_write):
            # and if that returns false, we need to EVICT and try again
            self.evict = True
            self.evict_page()

            return False
        else:
            return True



    def add_after_page_fault(self, vpn, read_or_write):
        for elem in self.frame_list:
            if not elem.in_use:
                elem.in_use = True
                elem.VPN = vpn
                bit_string = '{:0%db}' % 8
                elem.reference = bit_string.format(128)
                # if we're doing a write, need to set dirty bit
                if read_or_write == 'W':
                    elem.dirty = True
                # and return
                return True

        # if we make it this far, then all items are in use, so return false
        return False

四、 Second chance Algorithm (clock+reference bit)
在这里插入图片描述

设置循环队列类 Circular queue ,并在类中设置 指针 pointer;

设置(使用位,修改位)为:referencebit 和 Dirty;

主要步骤实现: (其余步骤与前三种算法类似)

 def find_victim(self):
        for index in range(0,self.qsize):
            elem = self.list[self.pointer]
            # if we find a page which is unreferenced (recently) and clean, that's our victim
            if elem.referencebit == False and elem.dirty == False:    # (0, 0)
                # return it's PPN, so we can index into it and remove it
                return elem.PPN
            elif elem.referencebit == False and elem.dirty == True:   # (0, 1)
                #skip, do nothing
                continue
            elif elem.referencebit == True and elem.dirty == False:   # (1, 0)
                elem.referencebit = False
                elem.dirty = False
            elif elem.referencebit == True and elem.dirty == True:    # (1, 1)
                elem.referencebit = False

            # use modulus of queue size to achieve a circular queue
            self.pointer = (self.pointer + 1) % self.qsize
            assert self.pointer <= self.qsize

        # if we get this far, no victim page was found,
        # need to flush __dirty unreferenced pages__ to disk
        # and then repeat

        return None

    def flush_dirty_and_unreferenced_pages(self):
        # NOTE: need to account for a DISK WRITE in clock algorithm

        # remove the dirty and unreferenced pages, count how many we removed
        number_of_disk_writes = 0
        for elem in self.list:
            if elem.dirty == True and elem.referencebit == False:
                elem.dirty = False
                number_of_disk_writes += 1

        return number_of_disk_writes
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值