Ejemplo n.º 1
0
    def __init__(self, cache_size=1000, p=0.5, ghostlist_size=-1):
        """

        :param cache_size:
        :param p: the position to separate cache for LRU1 and LRU2
        :param ghostlist_size:
        :return:
        """
        super().__init__(cache_size)
        self.p = p
        if ghostlist_size == -1:
            self.ghostlist_size = self.cache_size
        self.inserted_element = None  # used to record the element just inserted

        # dict/list2 is for referenced more than once
        self.linkedList1 = LinkedList()
        self.linkedList2 = LinkedList()
        self.lru_list_head_p1 = None
        self.lru_list_head_p2 = None

        self.cacheDict1 = dict(
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2 = dict(
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict1_ghost = defaultdict(
            lambda: 0
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2_ghost = defaultdict(
            lambda: 0
        )  # key -> linked list node (in reality, it should also contains value)
Ejemplo n.º 2
0
    def __init__(self, cache_size=1000, p=0.5, ghostlist_size=-1):
        '''

        :param cache_size:
        :param p: the position to separate cache for LRU1 and LRU2
        :param ghostlist_size:
        :return:
        '''
        super().__init__(cache_size)
        self.p = p
        if ghostlist_size == -1:
            self.ghostlist_size = self.cache_size

        # dict/list2 is for referenced more than once
        self.linkedList1 = LinkedList()
        self.linkedList2 = LinkedList()
        self.lru_list_head_p1 = None
        self.lru_list_head_p2 = None

        self.cacheDict1 = dict()  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2 = dict()  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict1_ghost = defaultdict(
            lambda: 0)  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2_ghost = defaultdict(
            lambda: 0)  # key -> linked list node (in reality, it should also contains value)
Ejemplo n.º 3
0
 def __init__(self, size=1000):
     self.max_size = size
     # this size includes holes, if want real element size use self.cacheLinkedList.size
     self.size = 0
     # self.cache   = OrderedDict()
     self.cacheLinkedList = LinkedList()
     self.cacheDict = dict()
     self.headPos = 1
     self.tailPos = 1
     self.numOfHoles = 0
     self.holePosSet = set()
Ejemplo n.º 4
0
 def __init__(self, size=1000):
     self.max_size = size
     # this size includes holes, if want real element size use self.cacheLinkedList.size
     self.size = 0
     # self.cache   = OrderedDict()
     self.cacheLinkedList = LinkedList()
     self.cacheDict = dict()
     self.headPos = 1
     self.tailPos = 1
     self.numOfHoles = 0
     self.holePosSet = set()
Ejemplo n.º 5
0
 def __init__(self, cache_size=1000):
     super().__init__(cache_size)
     self.cacheLinkedList = LinkedList()
     self.cacheDict = dict(
     )  # key -> linked list node (in reality, it should also contains value)
Ejemplo n.º 6
0
class LRU(cache):
    def __init__(self, cache_size=1000):
        super().__init__(cache_size)
        self.cacheLinkedList = LinkedList()
        self.cacheDict = dict(
        )  # key -> linked list node (in reality, it should also contains value)

    def __len__(self):
        return len(self.cacheDict)

    def checkElement(self, element):
        """
        :param element:
        :return: whether the given element is in the cache
        """
        if element in self.cacheDict:
            return True
        else:
            return False

    def _updateElement(self, element):
        """ the given element is in the cache, now update it to new location
        :param element:
        :return: None
        """

        node = self.cacheDict[element]
        self.cacheLinkedList.moveNodeToTail(node)

    def _insertElement(self, element, evict=True):
        """
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: evicted element or None
        """
        return_content = None
        if evict and self.cacheLinkedList.size >= self.cache_size:
            return_content = self._evictOneElement()

        node = self.cacheLinkedList.insertAtTail(element)
        self.cacheDict[element] = node
        return return_content

    def _printCacheLine(self):
        for i in self.cacheLinkedList:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)

        print(' ')

    def _evictOneElement(self):
        """
        evict one element from the cache line
        :return: content of evicted element
        """
        content = self.cacheLinkedList.removeFromHead()
        del self.cacheDict[content]
        return content

    def addElement(self, element):
        """
        :param element: the element in the reference, it can be in the cache, or not
        :return: None
        """
        if self.checkElement(element):
            self._updateElement(element)
            if len(self.cacheDict) != self.cacheLinkedList.size:
                print(
                    "1*********########### ERROR detected in LRU size #############***********"
                )
                print("{}: {}".format(self.cacheLinkedList.size,
                                      len(self.cacheDict)))
                import sys
                sys.exit(-1)
            return True
        else:
            self._insertElement(element)
            if len(self.cacheDict) != self.cacheLinkedList.size:
                print(
                    "2*********########### ERROR detected in LRU size #############***********"
                )
                print("{}: {}".format(self.cacheLinkedList.size,
                                      len(self.cacheDict)))
                import sys
                sys.exit(-1)
            return False

    def __repr__(self):
        return "LRU, given size: {}, current size: {}, {}".format(
            self.cache_size, self.cacheLinkedList.size,
            super().__repr__())
Ejemplo n.º 7
0
class modifiedLRU():
    def __init__(self, size=1000):
        self.max_size = size
        # this size includes holes, if want real element size use self.cacheLinkedList.size
        self.size = 0
        # self.cache   = OrderedDict()
        self.cacheLinkedList = LinkedList()
        self.cacheDict = dict()
        self.headPos = 1
        self.tailPos = 1
        self.numOfHoles = 0
        self.holePosSet = set()

    def checkElement(self, content):
        '''
        :param content: the content for search
        :return: whether the given element is in the cache
        '''
        if content in self.cacheDict:
            return True
        else:
            return False

    def getRank(self, content):
        '''

        :param content: the content of element, which is also the key in cacheDict
        :return: rank if in the cache, otherwise -1
        '''
        return self.cacheDict.get(content, (-1, -1))[0]

    def __updateElement__(self, element):
        ''' the given element is in the cache, now update it to new location
        :param element:
        :return: original rank
        '''
        rank = self.cacheDict.get(
            element, (-1, -1))[0] - self.headPos  # this may have holes
        rank = rank - math.floor(rank / self.size * self.numOfHoles)  # adjust
        if (rank < 0):
            print("waht, rank<0???\t" +
                  str(self.cacheDict.get(element, (-1, -1))[0]) + '\t' +
                  str(self.headPos) + '\t')
            print(
                str(rank) + "\t" +
                str(self.cacheDict.get(element, (-1, -1))[0] - self.headPos) +
                '\t' + str(self.size) + '\t' + str(self.numOfHoles))

        self.headPos -= 1
        self.cacheDict[element][0] = self.headPos
        self.numOfHoles += 1
        self.size += 1
        self.holePosSet.add(rank)

        self.cacheLinkedList.moveNodeToHead(self.cacheDict[element][1])
        return rank

    def __insertElement__(self, element):
        '''
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: True on success, False on failure
        '''
        node = self.cacheLinkedList.insertAtHead(element)
        self.headPos -= 1
        self.cacheDict[element] = [self.headPos, node]
        self.size += 1

        if self.cacheLinkedList.size > self.max_size:
            self.__evictOneElement__()
            self.tailPos -= 1

    def printLinkedList(self):
        for i in self.cacheLinkedList:
            print(i.content)

    def __evictOneElement__(self):
        '''
        evict one element from the cache line
        :return: True on success, False on failure
        '''
        content = self.cacheLinkedList.removeFromTail()
        del self.cacheDict[content]

    def addElement(self, element):
        '''
        :param element: the element in the reference, it can be in the cache, or not
        :return: -1 if not in cache, otherwise old rank
        '''
        if self.checkElement(element):
            return self.__updateElement__(element)
        else:
            self.__insertElement__(element)
            return -1

    def reArrange(self):
        pass
Ejemplo n.º 8
0
class ARC(cache):
    def __init__(self, cache_size=1000, p=0.5, ghostlist_size=-1):
        """

        :param cache_size:
        :param p: the position to separate cache for LRU1 and LRU2
        :param ghostlist_size:
        :return:
        """
        super().__init__(cache_size)
        self.p = p
        if ghostlist_size == -1:
            self.ghostlist_size = self.cache_size
        self.inserted_element = None  # used to record the element just inserted

        # dict/list2 is for referenced more than once
        self.linkedList1 = LinkedList()
        self.linkedList2 = LinkedList()
        self.lru_list_head_p1 = None
        self.lru_list_head_p2 = None

        self.cacheDict1 = dict(
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2 = dict(
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict1_ghost = defaultdict(
            lambda: 0
        )  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2_ghost = defaultdict(
            lambda: 0
        )  # key -> linked list node (in reality, it should also contains value)

    def checkElement(self, element):
        """
        :param element: the element for search
        :return: whether the given element is in the cache
        """
        if element in self.cacheDict1 or element in self.cacheDict2:
            return True
        else:
            return False

    def check_ghost_list(self, element):
        """
        :param element: the element for search
        :return: whether the given element is in the cache
        """
        if element in self.cacheDict1_ghost or element in self.cacheDict2_ghost:
            return True
        else:
            return False

    def _updateElement(self, element):
        """ the given element is in the cache, now update it to new location
        :param element:
        :return: None
        """
        if element in self.cacheDict1:
            # move to part2
            # get the node and remove from part1, size of part1 reduced by 1
            node = self.cacheDict1[element]

            if node == self.lru_list_head_p1:
                self.lru_list_head_p1 = self.lru_list_head_p1.next
            self.linkedList1.removeNode(node)

            del self.cacheDict1[element]

            # insert into part2
            self.linkedList2.insertNodeAtTail(node)
            self.cacheDict2[node.content] = node
            # delete one from part1, insert one into part2, the total size should not change, just the balance changes
            # check whether lru_list_head_p2 has been initialized or not
            if not self.lru_list_head_p2:
                self.lru_list_head_p2 = node

        else:
            node = self.cacheDict2[element]
            if node == self.lru_list_head_p2 and node.next:
                self.lru_list_head_p2 = self.lru_list_head_p2.next

            self.linkedList2.moveNodeToTail(node)

    def _insertElement(self, element):
        """
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: evicted element or None
        """
        return_content = None
        if self.linkedList1.size + self.linkedList2.size >= self.cache_size:
            # needs to evict one element, depend on ghost list to decide evict from part1 or part2
            return_content = self._evictOneElement(element)

        # insert into part 1
        node = self.linkedList1.insertAtTail(element)
        self.cacheDict1[element] = node
        if not self.lru_list_head_p1:
            self.lru_list_head_p1 = node
        self.inserted_element = element
        return return_content

    def _printCacheLine(self):
        print('list 1(including ghost list): ')
        for i in self.linkedList1:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)
        print('\nlist 2(including ghost list): ')
        for i in self.linkedList2:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)
        print(' ')

    def _evictOneElement(self):
        """
        evict one element from the cache line into ghost list, then check ghost list,
        if oversize, then evict one from ghost list
        :param: element: the missed request
        :return: content of element evicted into ghost list
        """
        return_content = None

        if self.inserted_element and self.inserted_element in self.cacheDict1_ghost and len(
                self.cacheDict2) > 0:
            # evict one from part2 LRU, add into ghost list
            return_content = content = self.lru_list_head_p2.content
            del self.cacheDict2[content]
            self.lru_list_head_p2 = self.lru_list_head_p2.next
            self.cacheDict2_ghost[content] += 1

            if (self.linkedList2.size -
                    len(self.cacheDict2)) > self.ghostlist_size:
                # the first part is the size of ghost list of part2
                content = self.linkedList2.removeFromHead()
                if self.cacheDict2_ghost[content] == 1:
                    del self.cacheDict2_ghost[content]
                else:
                    self.cacheDict2_ghost[content] -= 1
                assert (self.linkedList2.size -
                        len(self.cacheDict2)) == self.ghostlist_size

        elif self.inserted_element and self.inserted_element in self.cacheDict2_ghost and len(
                self.cacheDict1) > 0:
            # evict one from part1 LRU, add into ghost list
            return_content = content = self.lru_list_head_p1.content
            del self.cacheDict1[content]

            self.lru_list_head_p1 = self.lru_list_head_p1.next
            self.cacheDict1_ghost[content] += 1

            if (self.linkedList1.size -
                    len(self.cacheDict1)) > self.ghostlist_size:
                # the first part is the size of ghost list of part1
                content = self.linkedList1.removeFromHead()
                if self.cacheDict1_ghost[content] == 1:
                    del self.cacheDict1_ghost[content]
                else:
                    self.cacheDict1_ghost[content] -= 1
                assert (self.linkedList1.size -
                        len(self.cacheDict1)) == self.ghostlist_size

        else:
            # not in any ghost list, check p value
            if len(self.cacheDict2) == 0 or len(self.cacheDict1) / len(
                    self.cacheDict2) > self.p:
                # remove from part1
                return_content = content = self.lru_list_head_p1.content
                del self.cacheDict1[content]

                self.lru_list_head_p1 = self.lru_list_head_p1.next
                self.cacheDict1_ghost[content] += 1

                if (self.linkedList1.size -
                        len(self.cacheDict1)) > self.ghostlist_size:
                    # the first part is the size of ghost list of part1
                    content = self.linkedList1.removeFromHead()
                    if self.cacheDict1_ghost[content] == 1:
                        del self.cacheDict1_ghost[content]
                    else:
                        self.cacheDict1_ghost[content] -= 1
                    assert (self.linkedList1.size -
                            len(self.cacheDict1)) == self.ghostlist_size
            else:
                # remove from part2
                return_content = content = self.lru_list_head_p2.content
                del self.cacheDict2[content]

                self.lru_list_head_p2 = self.lru_list_head_p2.next
                self.cacheDict2_ghost[content] += 1

                if (self.linkedList2.size -
                        len(self.cacheDict2)) > self.ghostlist_size:
                    # the first part is the size of ghost list of part2
                    content = self.linkedList2.removeFromHead()
                    if self.cacheDict2_ghost[content] == 1:
                        del self.cacheDict2_ghost[content]
                    else:
                        self.cacheDict2_ghost[content] -= 1
                    assert (self.linkedList2.size -
                            len(self.cacheDict2)) == self.ghostlist_size

        return return_content

    # for debug
    def _check_lru_list_p(self):
        size1 = sum(i for i in self.cacheDict1_ghost.values())
        node1 = self.linkedList1.head.next
        for i in range(size1):
            node1 = node1.next
        assert node1 == self.lru_list_head_p1, "LRU list1 head pointer wrong"

        size2 = sum(i for i in self.cacheDict2_ghost.values())
        node2 = self.linkedList2.head.next
        for i in range(size2):
            node2 = node2.next
        print(size2)
        if node2:
            print(node2.content)
        else:
            print(node2)
        if self.lru_list_head_p2:
            print(self.lru_list_head_p2.content)
        else:
            print(self.lru_list_head_p2)
        assert node2 == self.lru_list_head_p2, "LRU list2 head pointer wrong"

    def addElement(self, element):
        """
        :param element: the element in the reference, it can be in the cache, or not
        :return: None
        """
        if self.checkElement(element):
            self._updateElement(element)
            # self.printCacheLine()
            # self._check_lru_list_p()
            return True
        else:
            self._insertElement(element)
            # self.printCacheLine()
            # self._check_lru_list_p()
            return False

    def __repr__(self):
        return "ARC, given size: {}, current part1 size: {}, part2 size: {}".format(
            self.cache_size, self.linkedList1.size, self.linkedList2.size)
Ejemplo n.º 9
0
 def __init__(self, cache_size=1000):
     super().__init__(cache_size)
     self.cacheLinkedList = LinkedList()
     self.cacheDict = dict(
     )  # store the reuse dist, thus dict: content->reuse dist, rank begins from 1
Ejemplo n.º 10
0
class LRU(cache):
    def __init__(self, cache_size=1000):
        super().__init__(cache_size)
        self.cacheLinkedList = LinkedList()
        self.cacheDict = dict(
        )  # store the reuse dist, thus dict: content->reuse dist, rank begins from 1

    def checkElement(self, content):
        '''
        :param content: the content for search
        :return: whether the given element is in the cache
        '''
        if content in self.cacheDict:
            return True
        else:
            return False

    def getReuseDist(self, content):
        '''

        :param content: the content of element, which is also the key in cacheDict
        :return: rank if in the cache, otherwise -1
        '''
        return self.cacheDict.get(content, -1)

    def _updateElement(self, element):
        ''' the given element is in the cache, now update it to new location
        :param element:
        :return: original rank
        '''
        rank = self.getReuseDist(element)
        # if rank >= 10:
        #     print("WWWWWWWWHHHHHHHHAAAAAAATTTTTTT")
        #     print(len(self.cacheDict))
        #     print(element)
        #     print(self.cacheDict)
        #     self.printLinkedList()
        # even if reuse distance is 0, it still needs at least one cache line
        self.cacheDict[element] = 1
        node = None
        counter = 0
        for node in self.cacheLinkedList:
            # print(node.content, end='\t')
            if node == None:
                print("**************stop**************")
            if node.content == element:
                break
            self.cacheDict[node.content] += 1
            counter += 1
        if counter != rank - 1:
            print("error")
            print(str(rank) + ":\t" + str(counter))
        self.cacheLinkedList.moveNodeToHead(node)
        return rank

    def _insertElement(self, element):
        '''
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: True on success, False on failure
        '''
        self.cacheLinkedList.insertAtHead(element)
        self.cacheDict[element] = 0
        # above is set as 0 because it will increment by 1 in the following loop
        for i in self.cacheDict.keys():
            self.cacheDict[i] += 1
        if self.cacheLinkedList.size > self.cache_size:
            self._evictOneElement()

    def printCacheLine(self):
        for i in self.cacheLinkedList:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)

        print(' ')

    def _evictOneElement(self):
        '''
        evict one element from the cache line
        :return: True on success, False on failure
        '''
        content = self.cacheLinkedList.removeFromTail()
        del self.cacheDict[content]

    def addElement(self, element):
        '''
        :param element: the element in the reference, it can be in the cache, or not
        :return: -1 if not in cache, otherwise old rank
        '''
        # print(element, end=': \t')
        if self.checkElement(element):
            rank = self._updateElement(element)
            # print(self.cacheDict)
            # self.printLinkedList()
            return rank
        else:
            self._insertElement(element)
            # print(self.cacheDict)
            # self.printLinkedList()
            return -1

    def __repr__(self):
        return "LRU, size: {}, {}".format(self.cache_size, super().__repr__())
Ejemplo n.º 11
0
class modifiedLRU():
    def __init__(self, size=1000):
        self.max_size = size
        # this size includes holes, if want real element size use self.cacheLinkedList.size
        self.size = 0
        # self.cache   = OrderedDict()
        self.cacheLinkedList = LinkedList()
        self.cacheDict = dict()
        self.headPos = 1
        self.tailPos = 1
        self.numOfHoles = 0
        self.holePosSet = set()

    def checkElement(self, content):
        '''
        :param content: the content for search
        :return: whether the given element is in the cache
        '''
        if content in self.cacheDict:
            return True
        else:
            return False

    def getRank(self, content):
        '''

        :param content: the content of element, which is also the key in cacheDict
        :return: rank if in the cache, otherwise -1
        '''
        return self.cacheDict.get(content, (-1, -1))[0]

    def __updateElement__(self, element):
        ''' the given element is in the cache, now update it to new location
        :param element:
        :return: original rank
        '''
        rank = self.cacheDict.get(element, (-1, -1))[0] - self.headPos  # this may have holes
        rank = rank - math.floor(rank / self.size * self.numOfHoles)  # adjust
        if (rank < 0):
            print("waht, rank<0???\t" + str(self.cacheDict.get(element, (-1, -1))[0]) + '\t' + str(self.headPos) + '\t')
            print(str(rank) + "\t" + str(self.cacheDict.get(element, (-1, -1))[0] - self.headPos) + '\t'
                  + str(self.size) + '\t' + str(self.numOfHoles))

        self.headPos -= 1
        self.cacheDict[element][0] = self.headPos
        self.numOfHoles += 1
        self.size += 1
        self.holePosSet.add(rank)

        self.cacheLinkedList.moveNodeToHead(self.cacheDict[element][1])
        return rank

    def __insertElement__(self, element):
        '''
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: True on success, False on failure
        '''
        node = self.cacheLinkedList.insertAtHead(element)
        self.headPos -= 1
        self.cacheDict[element] = [self.headPos, node]
        self.size += 1

        if self.cacheLinkedList.size > self.max_size:
            self.__evictOneElement__()
            self.tailPos -= 1

    def printLinkedList(self):
        for i in self.cacheLinkedList:
            print(i.content)

    def __evictOneElement__(self):
        '''
        evict one element from the cache line
        :return: True on success, False on failure
        '''
        content = self.cacheLinkedList.removeFromTail()
        del self.cacheDict[content]

    def addElement(self, element):
        '''
        :param element: the element in the reference, it can be in the cache, or not
        :return: -1 if not in cache, otherwise old rank
        '''
        if self.checkElement(element):
            return self.__updateElement__(element)
        else:
            self.__insertElement__(element)
            return -1

    def reArrange(self):
        pass
Ejemplo n.º 12
0
class ARC(cache):
    def __init__(self, cache_size=1000, p=0.5, ghostlist_size=-1):
        '''

        :param cache_size:
        :param p: the position to separate cache for LRU1 and LRU2
        :param ghostlist_size:
        :return:
        '''
        super().__init__(cache_size)
        self.p = p
        if ghostlist_size == -1:
            self.ghostlist_size = self.cache_size

        # dict/list2 is for referenced more than once
        self.linkedList1 = LinkedList()
        self.linkedList2 = LinkedList()
        self.lru_list_head_p1 = None
        self.lru_list_head_p2 = None

        self.cacheDict1 = dict()  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2 = dict()  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict1_ghost = defaultdict(
            lambda: 0)  # key -> linked list node (in reality, it should also contains value)
        self.cacheDict2_ghost = defaultdict(
            lambda: 0)  # key -> linked list node (in reality, it should also contains value)

    def checkElement(self, element):
        '''
        :param element: the element for search
        :return: whether the given element is in the cache
        '''
        if element in self.cacheDict1 or element in self.cacheDict2:
            return True
        else:
            return False

    def check_ghost_list(self, element):
        '''
        :param element: the element for search
        :return: whether the given element is in the cache
        '''
        if element in self.cacheDict1_ghost or element in self.cacheDict2_ghost:
            return True
        else:
            return False

    def _updateElement(self, element):
        ''' the given element is in the cache, now update it to new location
        :param element:
        :return: None
        '''
        if element in self.cacheDict1:
            # move to part2
            # get the node and remove from part1, size of part1 reduced by 1
            node = self.cacheDict1[element]
            # print("before remove")
            # for i in self.linkedList1:
            #     print(i.content, end='\t')
            # print("")
            if node == self.lru_list_head_p1:
                self.lru_list_head_p1 = self.lru_list_head_p1.next
            self.linkedList1.removeNode(node)
            # print("after remove")
            # for i in self.linkedList1:
            #     print(i.content, end='\t')
            # print("")

            del self.cacheDict1[element]

            # insert into part2
            self.linkedList2.insertNodeAtTail(node)
            self.cacheDict2[node.content] = node
            # delete one from part1, insert one into part2, the total size should not change, just the balance changes
            # check whether lru_list_head_p2 has been initialized or not
            if not self.lru_list_head_p2:
                self.lru_list_head_p2 = node


        else:
            node = self.cacheDict2[element]
            if node == self.lru_list_head_p2 and node.next:
                self.lru_list_head_p2 = self.lru_list_head_p2.next

            self.linkedList2.moveNodeToTail(node)

    def _insertElement(self, element):
        '''
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: evicted element or None
        '''
        return_content = None
        if self.linkedList1.size + self.linkedList2.size >= self.cache_size:
            # needs to evict one element, depend on ghost list to decide evict from part1 or part2
            return_content = self._evictOneElement(element)

        # insert into part 1
        node = self.linkedList1.insertAtTail(element)
        self.cacheDict1[element] = node
        if not self.lru_list_head_p1:
            self.lru_list_head_p1 = node
        return return_content

    def printCacheLine(self):
        print('list 1(including ghost list): ')
        for i in self.linkedList1:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)
        print('\nlist 2(including ghost list): ')
        for i in self.linkedList2:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)
        print(' ')

    def _evictOneElement(self, element):
        '''
        evict one element from the cache line into ghost list, then check ghost list,
        if oversize, then evict one from ghost list
        :param: element: the missed request
        :return: content of element evicted into ghost list
        '''
        return_content = None
        if element in self.cacheDict1_ghost and len(self.cacheDict2) > 0:
            # evict one from part2 LRU, add into ghost list
            return_content = content = self.lru_list_head_p2.content
            del self.cacheDict2[content]
            self.lru_list_head_p2 = self.lru_list_head_p2.next
            self.cacheDict2_ghost[content] += 1

            if (self.linkedList2.size - len(self.cacheDict2)) > self.ghostlist_size:
                # the first part is the size of ghost list of part2
                content = self.linkedList2.removeFromHead()
                if self.cacheDict2_ghost[content] == 1:
                    del self.cacheDict2_ghost[content]
                else:
                    self.cacheDict2_ghost[content] -= 1
                assert (self.linkedList2.size - len(self.cacheDict2)) == self.ghostlist_size


        elif element in self.cacheDict2_ghost and len(self.cacheDict1) > 0:
            # evict one from part1 LRU, add into ghost list
            return_content = content = self.lru_list_head_p1.content
            del self.cacheDict1[content]

            self.lru_list_head_p1 = self.lru_list_head_p1.next
            self.cacheDict1_ghost[content] += 1

            if (self.linkedList1.size - len(self.cacheDict1)) > self.ghostlist_size:
                # the first part is the size of ghost list of part1
                content = self.linkedList1.removeFromHead()
                if self.cacheDict1_ghost[content] == 1:
                    del self.cacheDict1_ghost[content]
                else:
                    self.cacheDict1_ghost[content] -= 1
                assert (self.linkedList1.size - len(self.cacheDict1)) == self.ghostlist_size

        else:
            # not in any ghost list, check p value
            if len(self.cacheDict2) == 0 or len(self.cacheDict1) / len(self.cacheDict2) > self.p:
                # remove from part1
                return_content = content = self.lru_list_head_p1.content
                del self.cacheDict1[content]

                self.lru_list_head_p1 = self.lru_list_head_p1.next
                self.cacheDict1_ghost[content] += 1

                if (self.linkedList1.size - len(self.cacheDict1)) > self.ghostlist_size:
                    # the first part is the size of ghost list of part1
                    content = self.linkedList1.removeFromHead()
                    if self.cacheDict1_ghost[content] == 1:
                        del self.cacheDict1_ghost[content]
                    else:
                        self.cacheDict1_ghost[content] -= 1
                    assert (self.linkedList1.size - len(self.cacheDict1)) == self.ghostlist_size
            else:
                # remove from part2
                return_content = content = self.lru_list_head_p2.content
                del self.cacheDict2[content]

                self.lru_list_head_p2 = self.lru_list_head_p2.next
                self.cacheDict2_ghost[content] += 1

                if (self.linkedList2.size - len(self.cacheDict2)) > self.ghostlist_size:
                    # the first part is the size of ghost list of part2
                    content = self.linkedList2.removeFromHead()
                    if self.cacheDict2_ghost[content] == 1:
                        del self.cacheDict2_ghost[content]
                    else:
                        self.cacheDict2_ghost[content] -= 1
                    assert (self.linkedList2.size - len(self.cacheDict2)) == self.ghostlist_size

        return return_content

    # for debug
    def _check_lru_list_p(self):
        size1 = sum(i for i in self.cacheDict1_ghost.values())
        node1 = self.linkedList1.head.next
        for i in range(size1):
            node1 = node1.next
        assert node1 == self.lru_list_head_p1, "LRU list1 head pointer wrong"

        size2 = sum(i for i in self.cacheDict2_ghost.values())
        node2 = self.linkedList2.head.next
        for i in range(size2):
            node2 = node2.next
        print(size2)
        if node2:
            print(node2.content)
        else:
            print(node2)
        if self.lru_list_head_p2:
            print(self.lru_list_head_p2.content)
        else:
            print(self.lru_list_head_p2)
        assert node2 == self.lru_list_head_p2, "LRU list2 head pointer wrong"

    def addElement(self, element):
        '''
        :param element: the element in the reference, it can be in the cache, or not
        :return: None
        '''
        if self.checkElement(element):
            self._updateElement(element)
            # self.printCacheLine()
            # self._check_lru_list_p()
            return True
        else:
            self._insertElement(element)
            # self.printCacheLine()
            # self._check_lru_list_p()
            return False

    def __repr__(self):
        return "ARC, given size: {}, current part1 size: {}, part2 size: {}".format(
            self.cache_size, self.linkedList1.size, self.linkedList2.size)
Ejemplo n.º 13
0
 def __init__(self, cache_size=1000):
     super().__init__(cache_size)
     self.cacheLinkedList = LinkedList()
     self.cacheDict = dict()  # store the reuse dist, thus dict: content->reuse dist, rank begins from 1
Ejemplo n.º 14
0
class LRU(cache):
    def __init__(self, cache_size=1000):
        super().__init__(cache_size)
        self.cacheLinkedList = LinkedList()
        self.cacheDict = dict()  # store the reuse dist, thus dict: content->reuse dist, rank begins from 1

    def checkElement(self, content):
        '''
        :param content: the content for search
        :return: whether the given element is in the cache
        '''
        if content in self.cacheDict:
            return True
        else:
            return False

    def getReuseDist(self, content):
        '''

        :param content: the content of element, which is also the key in cacheDict
        :return: rank if in the cache, otherwise -1
        '''
        return self.cacheDict.get(content, -1)

    def _updateElement(self, element):
        ''' the given element is in the cache, now update it to new location
        :param element:
        :return: original rank
        '''
        rank = self.getReuseDist(element)
        # if rank >= 10:
        #     print("WWWWWWWWHHHHHHHHAAAAAAATTTTTTT")
        #     print(len(self.cacheDict))
        #     print(element)
        #     print(self.cacheDict)
        #     self.printLinkedList()
        # even if reuse distance is 0, it still needs at least one cache line
        self.cacheDict[element] = 1
        node = None
        counter = 0
        for node in self.cacheLinkedList:
            # print(node.content, end='\t')
            if node == None:
                print("**************stop**************")
            if node.content == element:
                break
            self.cacheDict[node.content] += 1
            counter += 1
        if counter != rank - 1:
            print("error")
            print(str(rank) + ":\t" + str(counter))
        self.cacheLinkedList.moveNodeToHead(node)
        return rank

    def _insertElement(self, element):
        '''
        the given element is not in the cache, now insert it into cache
        :param element:
        :return: True on success, False on failure
        '''
        self.cacheLinkedList.insertAtHead(element)
        self.cacheDict[element] = 0
        # above is set as 0 because it will increment by 1 in the following loop
        for i in self.cacheDict.keys():
            self.cacheDict[i] += 1
        if self.cacheLinkedList.size > self.cache_size:
            self._evictOneElement()

    def printCacheLine(self):
        for i in self.cacheLinkedList:
            try:
                print(i.content, end='\t')
            except:
                print(i.content)

        print(' ')

    def _evictOneElement(self):
        '''
        evict one element from the cache line
        :return: True on success, False on failure
        '''
        content = self.cacheLinkedList.removeFromTail()
        del self.cacheDict[content]

    def addElement(self, element):
        '''
        :param element: the element in the reference, it can be in the cache, or not
        :return: -1 if not in cache, otherwise old rank
        '''
        # print(element, end=': \t')
        if self.checkElement(element):
            rank = self._updateElement(element)
            # print(self.cacheDict)
            # self.printLinkedList()
            return rank
        else:
            self._insertElement(element)
            # print(self.cacheDict)
            # self.printLinkedList()
            return -1

    def __repr__(self):
        return "LRU, size: {}, {}".format(self.cache_size, super().__repr__())