Compare commits
13 Commits
74cad036f8
...
master
Author | SHA1 | Date | |
---|---|---|---|
1916781bbb | |||
539df093a3 | |||
49ef72e1ea | |||
49410552c6 | |||
1a84f77192 | |||
552953591e | |||
55345b7c76 | |||
a21fc9e08d | |||
1860adceff | |||
b577a5fe02 | |||
c742d6b58d | |||
21ba17c7b6 | |||
851f43206e |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
*.o
|
*.o
|
||||||
*
|
*.
|
||||||
|
*.txt
|
||||||
*.vscode
|
*.vscode
|
||||||
|
*.out
|
||||||
|
*.exe
|
||||||
|
51
.vscode/settings.json
vendored
51
.vscode/settings.json
vendored
@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"iostream": "cpp",
|
|
||||||
"array": "cpp",
|
|
||||||
"atomic": "cpp",
|
|
||||||
"bit": "cpp",
|
|
||||||
"*.tcc": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"compare": "cpp",
|
|
||||||
"concepts": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"list": "cpp",
|
|
||||||
"string": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"functional": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"string_view": "cpp",
|
|
||||||
"system_error": "cpp",
|
|
||||||
"tuple": "cpp",
|
|
||||||
"type_traits": "cpp",
|
|
||||||
"utility": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"istream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"numbers": "cpp",
|
|
||||||
"ostream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"typeinfo": "cpp",
|
|
||||||
"fstream": "cpp",
|
|
||||||
"sstream": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
91
2Q_cache.h
91
2Q_cache.h
@ -18,43 +18,83 @@ private:
|
|||||||
std::list <int> q2; //slow queue - if page asked at the first time put it to q2, if itasked from q2 it put it to q1,
|
std::list <int> q2; //slow queue - if page asked at the first time put it to q2, if itasked from q2 it put it to q1,
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int tic_number = 0;
|
||||||
|
|
||||||
TwoCache(size_t q1sz, size_t q2sz): cpct_q1(q1sz), cpct_q2(q2sz) {} //ctor
|
TwoCache(size_t q1sz, size_t q2sz): cpct_q1(q1sz), cpct_q2(q2sz) {} //ctor
|
||||||
|
|
||||||
void put_page(int id) {
|
void put_page(int id) {
|
||||||
|
//std::cout << "id: " << id << std::endl;
|
||||||
|
|
||||||
if (umap1.find(id) != umap1.end()) { //page is found, nothing to do (fast case)
|
if (umap1.find(id) != umap1.end()) { //page is found, nothing to do (fast case)
|
||||||
return;
|
//std::cout << "id ="<<id<<" TIC!\n";
|
||||||
} else if (umap2.find(id) != umap2.end()) {
|
|
||||||
q2.erase(umap2[id]); //if page is in slow put it in fast
|
tic_number++;
|
||||||
if (q1.size() < cpct_q1) {
|
|
||||||
q1.push_front(id);
|
//print_info();
|
||||||
umap1[id] = q1.begin();
|
|
||||||
} else {
|
|
||||||
int lru_page = q1.back(); //if fast is overflow - delete
|
|
||||||
q1.pop_back();
|
|
||||||
umap1.erase(lru_page);
|
|
||||||
q1.push_front(id);
|
|
||||||
umap1[id] = q1.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
} else if (umap2.find(id) != umap2.end()) {
|
||||||
|
//std::cout << "id ="<<id<<" TIC!\n";
|
||||||
|
|
||||||
|
tic_number++;
|
||||||
|
|
||||||
|
q2.erase(umap2[id]);
|
||||||
|
|
||||||
|
umap2.erase(id);
|
||||||
|
|
||||||
|
|
||||||
|
if (q1.size() < cpct_q1) {
|
||||||
|
|
||||||
|
//print_info();
|
||||||
|
|
||||||
|
q1.push_front(id);
|
||||||
|
|
||||||
|
umap1[id] = q1.begin();
|
||||||
|
|
||||||
|
//print_info();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//print_info();
|
||||||
|
|
||||||
|
auto lru_page = q1.back(); //if fast is overflow - delete
|
||||||
|
umap1.erase(lru_page);
|
||||||
|
q1.pop_back();
|
||||||
|
q1.push_front(id);
|
||||||
|
umap1[id] = q1.begin();
|
||||||
|
|
||||||
|
//print_info();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (q2.size() < cpct_q2) { //if not in cache put it in slow
|
} else if (q2.size() < cpct_q2) { //if not in cache put it in slow
|
||||||
|
|
||||||
|
//print_info();
|
||||||
|
|
||||||
q2.push_front(id);
|
q2.push_front(id);
|
||||||
umap2[id] = q2.begin();
|
umap2[id] = q2.begin();
|
||||||
|
|
||||||
|
//print_info();
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else { //if slow is overflow - pop
|
} else { //if slow is overflow - pop
|
||||||
int lru_page = q2.back();
|
|
||||||
q2.pop_back();
|
//print_info();
|
||||||
|
|
||||||
|
int lru_page = q2.back(); //if fast is overflow - delete
|
||||||
umap2.erase(lru_page);
|
umap2.erase(lru_page);
|
||||||
|
q2.pop_back();
|
||||||
q2.push_front(id);
|
q2.push_front(id);
|
||||||
umap2[id] = q2.begin();
|
umap2[id] = q2.begin();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//print_info();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_info() {
|
void print_info() {
|
||||||
|
std::cout <<__LINE__ << " " << __FILE__<< std::endl;
|
||||||
std::cout << "\nq1 (the most usable): ";
|
std::cout << "\nq1 (the most usable): ";
|
||||||
for (auto i = q1.begin(); i != q1.end(); i++) {
|
for (auto i = q1.begin(); i != q1.end(); i++) {
|
||||||
std::cout << *i << " ";
|
std::cout << *i << " ";
|
||||||
@ -63,7 +103,24 @@ public:
|
|||||||
for (auto i = q2.begin(); i != q2.end(); i++) {
|
for (auto i = q2.begin(); i != q2.end(); i++) {
|
||||||
std::cout << *i << " ";
|
std::cout << *i << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Umap1:\n";
|
||||||
|
|
||||||
|
for (auto it = umap1.begin(); it != umap1.end(); ++it) {
|
||||||
|
std::cout << "Key: " << (it->first) << ", Val: " << *(it->second) << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Umap2:\n";
|
||||||
|
|
||||||
|
for (auto it = umap2.begin(); it != umap2.end(); ++it) {
|
||||||
|
std::cout << "Key: " << it->first << ", Val: " << *(it->second) << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_info () { //to easy compare with tests;
|
std::string string_info () { //to easy compare with tests;
|
||||||
|
69
Ideal_cache.h
Normal file
69
Ideal_cache.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
class Ideal_Cache {
|
||||||
|
private:
|
||||||
|
int capacity;
|
||||||
|
std::vector<int> cache;
|
||||||
|
std::unordered_map<int, int> cacheMap; // Для быстрого доступа к индексам
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ideal_Cache(size_t capacity) : capacity(capacity) {}
|
||||||
|
|
||||||
|
int tic_number = 0;
|
||||||
|
|
||||||
|
void get_request_vector(const std::vector<int>& requests) {
|
||||||
|
// смотрим есть ли айди в кэше
|
||||||
|
// Есть - тик
|
||||||
|
// Нет - смотрим размер, если размер не полный добавляем в кэш
|
||||||
|
// если размер полный, то уберем тот, который позже всех встретится
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < requests.size(); ++i) {
|
||||||
|
int item = requests[i];
|
||||||
|
|
||||||
|
if (cacheMap.find(item) != cacheMap.end()) {
|
||||||
|
tic_number++; //tic
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache.size() < capacity) {
|
||||||
|
cache.push_back(item);
|
||||||
|
cacheMap[item] = cache.size() - 1;
|
||||||
|
} else {
|
||||||
|
int farthest = -1;
|
||||||
|
int indexToRemove = -1;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < cache.size(); ++j) {
|
||||||
|
auto nextIndex = std::find(requests.begin() + i, requests.end(), cache[j]); //находим следующее вхождение (начиная с i ого тк предыдущие обработались)
|
||||||
|
|
||||||
|
if (nextIndex == requests.end()) {
|
||||||
|
indexToRemove = j; //В конце удалим последний
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
int nextIdx = std::distance(requests.begin(), nextIndex);
|
||||||
|
if (nextIdx > farthest) {
|
||||||
|
farthest = nextIdx;
|
||||||
|
indexToRemove = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheMap.erase(cache[indexToRemove]);
|
||||||
|
cache[indexToRemove] = item;
|
||||||
|
cacheMap[item] = indexToRemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void info() const {
|
||||||
|
std::cout << "ideal cache: ";
|
||||||
|
for (int item : cache) {
|
||||||
|
std::cout << item << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
};
|
22
Readme.md
Normal file
22
Readme.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Алгоритм кэширования 2Q
|
||||||
|
Алгоритм кэширования 2Q (Two Queues) представляет собой метод управления кэш-памятью. Этот алгоритм состоит из двух очередей: q1 и q2. q1 является буфером, в который добавляются данные только в начале и замещаются из конца, а q2 используется для хранения "недавно использованных" данных.
|
||||||
|
# Тестирование
|
||||||
|
Генератор тестов - test_gen.py спрашивает количество тестов и создает pytests.txt
|
||||||
|
# Запуск тестов
|
||||||
|
make test - собирает программу затем
|
||||||
|
./cache_test "test_file_name"
|
||||||
|
## Напиример:
|
||||||
|
./cache_test pytests.txt
|
||||||
|
# Принцип работы
|
||||||
|
Когда данные добавляются в кэш, они помещаются в начало q1.
|
||||||
|
Если данные извлекаются из кэша, они перемещаются из q1 в начало q2.
|
||||||
|
Если данные снова запрашиваются и они находятся в q2, они перемещаются в конец q1.
|
||||||
|
Если данные снова запрашиваются и их уже нет в кэше, они добавляются в начало q1, а если q1 заполнена, то данные из конца q1 удаляются и добавляются новые данные в начало q1.
|
||||||
|
# Преимущества
|
||||||
|
## Эффективность:
|
||||||
|
алгоритм 2Q обладает хорошей производительностью и способен эффективно управлять кэш-памятью.
|
||||||
|
## Адаптивность:
|
||||||
|
алгоритм автоматически регулируется в зависимости от обращаемости данных, приспосабливаясь к изменениям в запросах.
|
||||||
|
## Недостатки
|
||||||
|
Не подходит для всех типов данных: алгоритм 2Q неэффективен для случаев, когда данные необходимо хранить в определённом порядке.
|
||||||
|
Сложность реализации: реализация алгоритма кэширования 2Q может быть более сложной, чем у других методов управления кэш-памятью.
|
BIN
cache_test
Executable file
BIN
cache_test
Executable file
Binary file not shown.
@ -1,7 +1,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "2Q_cache.h"
|
#include "2Q_cache.h"
|
||||||
|
#include "Ideal_cache.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
const char* default_test_file = "tests.txt";
|
||||||
|
|
||||||
|
|
||||||
int cache_test(std::string file_name) {
|
int cache_test(std::string file_name) {
|
||||||
@ -16,26 +21,35 @@ int cache_test(std::string file_name) {
|
|||||||
|
|
||||||
|
|
||||||
std::string test_line, answer_line;
|
std::string test_line, answer_line;
|
||||||
int fast_q_sz, slow_q_sz, num_of_calls, page_id, test_number = 0;
|
int fast_q_sz, slow_q_sz, num_of_calls, page_id, test_number = 0, test_passed = 0, test_failed = 0;
|
||||||
|
|
||||||
while (std::getline(file, test_line)) {
|
while (std::getline(file, test_line)) {
|
||||||
std::stringstream ss(test_line);
|
std::stringstream ss(test_line);
|
||||||
ss >> fast_q_sz >> slow_q_sz>>num_of_calls; //read input
|
ss >> fast_q_sz >> slow_q_sz>>num_of_calls; //read input
|
||||||
|
|
||||||
TwoCache cache(fast_q_sz, slow_q_sz); //initialising
|
TwoCache cache(fast_q_sz, slow_q_sz); //initialising
|
||||||
|
Ideal_Cache ideal_cache(fast_q_sz + slow_q_sz);
|
||||||
|
|
||||||
|
std::vector <int> requests;
|
||||||
|
|
||||||
for (int i = 0; i < num_of_calls; i++) { //executing
|
for (int i = 0; i < num_of_calls; i++) { //executing
|
||||||
ss >> page_id;
|
ss >> page_id;
|
||||||
cache.put_page(page_id);
|
cache.put_page(page_id);
|
||||||
|
requests.push_back(page_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ideal_cache.get_request_vector(requests);
|
||||||
|
|
||||||
std::getline(file, answer_line);
|
std::getline(file, answer_line);
|
||||||
|
|
||||||
if (cache.string_info() == answer_line) { //compare answers
|
if (cache.string_info() == answer_line) { //compare answers
|
||||||
std::cout << "test - " << test_number << " passed\n";
|
std::cout << "test - " << test_number << " passed\n";
|
||||||
|
std::cout << "ideal tics/your tics " << ideal_cache.tic_number << "/" << cache.tic_number << std::endl;
|
||||||
|
test_passed++;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "test - " << test_number << " failed\n";
|
std::cout << "test - " << test_number << " failed\n";
|
||||||
std::cout << "right answer - " << answer_line << "your answer - " << cache.string_info() << std::endl;
|
std::cout << "right answer - " << answer_line << "your answer - " << cache.string_info() << std::endl;
|
||||||
|
test_failed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
test_number++;
|
test_number++;
|
||||||
@ -43,11 +57,15 @@ int cache_test(std::string file_name) {
|
|||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
std::cout << "\nNumber of tests = "<< test_number << "\nTests passed = " << test_passed << "\nTests failed = " << test_failed << "\n";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char* argv[]) {
|
||||||
cache_test("tests.txt");
|
if (argc == 0) {
|
||||||
|
cache_test(default_test_file);
|
||||||
|
} else {
|
||||||
|
cache_test(argv[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
makefile
20
makefile
@ -1,10 +1,6 @@
|
|||||||
|
|
||||||
TARGET = Q2
|
TARGET = Q2
|
||||||
|
|
||||||
CXX = g++
|
CXX = g++
|
||||||
|
|
||||||
CXXFLAGS = -Wall -Wextra -std=c++11
|
|
||||||
|
|
||||||
SRCS = main.cpp
|
SRCS = main.cpp
|
||||||
TEST = cache_test.cpp
|
TEST = cache_test.cpp
|
||||||
|
|
||||||
@ -16,16 +12,22 @@ $(TARGET): $(OBJS)
|
|||||||
$(CXX) -o $@ $^
|
$(CXX) -o $@ $^
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
$(CXX) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(CXX) $(CXXFLAGS) $(TEST) -o cache_test
|
$(CXX) $(CPPFLAGS) $(TEST) -o cache_test
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TARGET) $(TEST)
|
rm -f $(OBJS) $(TARGET) cache_test
|
||||||
|
|
||||||
run: $(TARGET)
|
run: $(TARGET)
|
||||||
./$(TARGET)
|
./$(TARGET)
|
||||||
|
|
||||||
.PHONY: all clean run
|
ifeq ($(OS), Windows_NT)
|
||||||
|
clean:
|
||||||
|
del /Q $(OBJS) $(TARGET) cache_test
|
||||||
|
run: $(TARGET)
|
||||||
|
$(TARGET).exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all clean run test
|
67
test_gen.py
Normal file
67
test_gen.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class Cache:
|
||||||
|
def __init__(self, cpst1, cpst2):
|
||||||
|
self.cpst1 = cpst1
|
||||||
|
self.cpst2 = cpst2
|
||||||
|
|
||||||
|
self.list1 = []
|
||||||
|
self.list2 = []
|
||||||
|
|
||||||
|
def put_page(self, id:int):
|
||||||
|
if(id in self.list1):
|
||||||
|
return 0 #tic
|
||||||
|
elif (id in self.list2):
|
||||||
|
self.list2.remove(id) #tic
|
||||||
|
if(len(self.list1) < self.cpst1):
|
||||||
|
self.list1.insert(0, id)
|
||||||
|
else:
|
||||||
|
self.list1.pop(-1)
|
||||||
|
self.list1.insert(0, id)
|
||||||
|
|
||||||
|
elif (len(self.list2) < self.cpst2):
|
||||||
|
self.list2.insert(0, id)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
self.list2.pop(-1)
|
||||||
|
self.list2.insert(0, id)
|
||||||
|
|
||||||
|
def ret_cache(self):
|
||||||
|
return self.list1 + self.list2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
number_of_test = int(input())
|
||||||
|
|
||||||
|
with open('pytests.txt', 'w+') as file:
|
||||||
|
|
||||||
|
for i in range(number_of_test):
|
||||||
|
vect = []
|
||||||
|
szq1 = random.randint(5, 10)
|
||||||
|
szq2 = random.randint(5, 10)
|
||||||
|
num_of_requests = (random.randint(1, 1000000))
|
||||||
|
|
||||||
|
cache = Cache(szq1, szq2)
|
||||||
|
|
||||||
|
vect.append(szq1)
|
||||||
|
vect.append(szq2)
|
||||||
|
vect.append(num_of_requests)
|
||||||
|
|
||||||
|
for j in range(num_of_requests):
|
||||||
|
id = random.randint(0, 100)
|
||||||
|
|
||||||
|
vect.append(id)
|
||||||
|
cache.put_page(id)
|
||||||
|
|
||||||
|
file.write(str(vect)[1:-1].replace(", ", " "))
|
||||||
|
file.write('\n')
|
||||||
|
|
||||||
|
file.write(str(cache.ret_cache())[1:-1].replace(", ", " "))
|
||||||
|
file.write('\n')
|
||||||
|
|
Reference in New Issue
Block a user