|
2 | 2 | #include <string> |
3 | 3 | #include <iostream> |
4 | 4 | #include <cstdlib> |
| 5 | +#include <memory> |
| 6 | +#include <type_traits> |
5 | 7 |
|
6 | | -int main (int argc, char** argv) |
| 8 | +namespace dyad_residency |
7 | 9 | { |
8 | | - using namespace dyad_residency; |
9 | 10 |
|
10 | | - int seed = 0; |
| 11 | +enum Set_Type {Set_LRU_, Set_MRU_, Set_Prio_, Set_End_}; |
| 12 | + |
11 | 13 |
|
12 | | - if (argc > 2) { |
| 14 | +template<Set_Type V> |
| 15 | +using st = std::integral_constant<Set_Type, V>; |
| 16 | + |
| 17 | +std::unique_ptr<Cache<Set_LRU>> make_cache(st<Set_LRU_>, unsigned size, unsigned ways) { |
| 18 | + return std::unique_ptr<Cache<Set_LRU>>(new Cache<Set_LRU>(size, ways)); |
| 19 | +} |
| 20 | +std::unique_ptr<Cache<Set_MRU>> make_cache(st<Set_MRU_>, unsigned size, unsigned ways) { |
| 21 | + return std::unique_ptr<Cache<Set_MRU>>(new Cache<Set_MRU>(size, ways)); |
| 22 | +} |
| 23 | +std::unique_ptr<Cache<Set_Prioritized>> make_cache(st<Set_Prio_>, unsigned size, unsigned ways) { |
| 24 | + return std::unique_ptr<Cache<Set_Prioritized>>(new Cache<Set_Prioritized>(size, ways)); |
| 25 | +} |
| 26 | + |
| 27 | +template< template<typename S> typename C, typename S> |
| 28 | +int run_cache (int seed, |
| 29 | + std::unique_ptr<C<S>>& cacheL1, |
| 30 | + std::unique_ptr<C<S>>& cacheL2, |
| 31 | + const std::vector<std::string>& acc) |
| 32 | +{ |
| 33 | + bool hitL1 = false; |
| 34 | + |
| 35 | + if (!cacheL1 || !cacheL2) { |
| 36 | + std::cerr << "Cannot allocate cache." << std::endl; |
13 | 37 | return EXIT_FAILURE; |
14 | 38 | } |
15 | | - if (argc == 2) { |
16 | | - seed = atoi (argv[1]); |
17 | | - } |
| 39 | + cacheL1->set_seed (seed + 104677u); |
| 40 | + cacheL1->set_level ("L1"); |
| 41 | + cacheL2->set_seed (seed + 104681u); |
| 42 | + cacheL2->set_level (" L2"); |
18 | 43 |
|
19 | | - typedef std::vector<std::string> access; |
20 | | - access acc; // access pattern in terms of the block index |
21 | | - acc.push_back ("1"); |
22 | | - acc.push_back ("4"); |
23 | | - acc.push_back ("2"); |
24 | | - acc.push_back ("3"); |
25 | | - acc.push_back ("5"); |
26 | | - acc.push_back ("5"); |
27 | | - acc.push_back ("3"); |
28 | | - bool hitL1; |
29 | | - |
30 | | -#if 1 |
31 | | - Cache<Set_LRU> cacheL1 (4, 2); // 2-way set-associative |
32 | | - Cache<Set_LRU> cacheL2 (8, 2); // cache capacity = 8 blocks |
33 | | -#else |
34 | | - Cache<Set_LRU> cacheL1 (4, 0); // cache capacity = 4 blocks |
35 | | - Cache<Set_LRU> cacheL2 (8, 0); // fully-associative |
36 | | -#endif |
37 | | - cacheL1.set_seed (seed + 104677u); |
38 | | - cacheL1.set_level ("L1"); |
39 | | - cacheL2.set_seed (seed + 104681u); |
40 | | - cacheL2.set_level (" L2"); |
41 | | - |
42 | | - std::cout << "L1 Cache size set to " << cacheL1.size () << " blocks" << std::endl; |
43 | | - std::cout << "L2 Cache size set to " << cacheL2.size () << " blocks" << std::endl; |
| 44 | + std::cout << "L1 Cache size set to " << cacheL1->size () << " blocks" << std::endl; |
| 45 | + std::cout << "L2 Cache size set to " << cacheL2->size () << " blocks" << std::endl; |
44 | 46 |
|
45 | 47 | std::cout << "accessing block 1, 4, 2, and 3 in order" << std::endl; |
46 | | - for (unsigned int i = 0; (i < cacheL1.size ()) && (i < acc.size ()); i++) { |
47 | | - hitL1 = cacheL1.access (acc[i]); |
48 | | - if (!hitL1) cacheL2.access (acc[i]); |
| 48 | + for (unsigned int i = 0; (i < cacheL1->size ()) && (i < acc.size ()); i++) { |
| 49 | + hitL1 = cacheL1->access (acc[i]); |
| 50 | + if (!hitL1) cacheL2->access (acc[i]); |
49 | 51 | } |
50 | 52 |
|
51 | 53 | std::cout << "-------------------------L1----------------------------" << std::endl; |
52 | | - std::cout << cacheL1 << std::endl; |
| 54 | + std::cout << *cacheL1 << std::endl; |
53 | 55 | std::cout << "-------------------------L2----------------------------" << std::endl; |
54 | | - std::cout << cacheL2 << std::endl; |
| 56 | + std::cout << *cacheL2 << std::endl; |
55 | 57 | std::cout << "-------------------------------------------------------" << std::endl; |
56 | 58 |
|
57 | 59 | std::cout << "accessing block 5" << std::endl; |
58 | | - hitL1 = cacheL1.access (acc[4]); |
59 | | - if (!hitL1) cacheL2.access (acc[4]); |
| 60 | + hitL1 = cacheL1->access (acc[4]); |
| 61 | + if (!hitL1) cacheL2->access (acc[4]); |
60 | 62 |
|
61 | 63 | std::cout << "-------------------------L1----------------------------" << std::endl; |
62 | | - std::cout << cacheL1 << std::endl; |
| 64 | + std::cout << *cacheL1 << std::endl; |
63 | 65 | std::cout << "-------------------------L2----------------------------" << std::endl; |
64 | | - std::cout << cacheL2 << std::endl; |
| 66 | + std::cout << *cacheL2 << std::endl; |
65 | 67 | std::cout << "-------------------------------------------------------" << std::endl; |
66 | 68 |
|
67 | 69 | std::cout << "accessing block 1, 4, 2, 3, 5, 5, and 3 in order" << std::endl; |
68 | 70 | for (unsigned int i = 0; i < acc.size (); i++) { |
69 | | - hitL1 = cacheL1.access (acc[i]); |
70 | | - if (!hitL1) cacheL2.access (acc[i]); |
| 71 | + hitL1 = cacheL1->access (acc[i]); |
| 72 | + if (!hitL1) cacheL2->access (acc[i]); |
71 | 73 | } |
72 | 74 |
|
73 | 75 | std::cout << "-------------------------L1----------------------------" << std::endl; |
74 | | - std::cout << cacheL1 << std::endl; |
| 76 | + std::cout << *cacheL1 << std::endl; |
75 | 77 | std::cout << "-------------------------L2----------------------------" << std::endl; |
76 | | - std::cout << cacheL2 << std::endl; |
| 78 | + std::cout << *cacheL2 << std::endl; |
77 | 79 | std::cout << "-------------------------------------------------------" << std::endl; |
78 | 80 |
|
79 | 81 | return EXIT_SUCCESS; |
80 | 82 | } |
| 83 | + |
| 84 | +int cache_demo (const Set_Type st, int seed, |
| 85 | + unsigned sizeL1, unsigned waysL1, |
| 86 | + unsigned sizeL2, unsigned waysL2, |
| 87 | + const std::vector<std::string>& acc) |
| 88 | +{ |
| 89 | + if (st == Set_LRU_) { |
| 90 | + auto cacheL1 = std::unique_ptr<Cache<Set_LRU>>(new Cache<Set_LRU> (sizeL1, waysL1)); |
| 91 | + auto cacheL2 = std::unique_ptr<Cache<Set_LRU>>(new Cache<Set_LRU> (sizeL2, waysL2)); |
| 92 | + return run_cache (seed, cacheL1, cacheL2, acc); |
| 93 | + } else if (st == Set_MRU_) { |
| 94 | + auto cacheL1 = std::unique_ptr<Cache<Set_MRU>>(new Cache<Set_MRU> (sizeL1, waysL1)); |
| 95 | + auto cacheL2 = std::unique_ptr<Cache<Set_MRU>>(new Cache<Set_MRU> (sizeL2, waysL2)); |
| 96 | + return run_cache (seed, cacheL1, cacheL2, acc); |
| 97 | + } else if (st == Set_Prio_) { |
| 98 | + auto cacheL1 = std::unique_ptr<Cache<Set_Prioritized>>(new Cache<Set_Prioritized> (sizeL1, waysL1)); |
| 99 | + auto cacheL2 = std::unique_ptr<Cache<Set_Prioritized>>(new Cache<Set_Prioritized> (sizeL2, waysL2)); |
| 100 | + return run_cache (seed, cacheL1, cacheL2, acc); |
| 101 | + } |
| 102 | + return EXIT_FAILURE; |
| 103 | +} |
| 104 | + |
| 105 | +} // end of namespace dyad_Residency |
| 106 | + |
| 107 | + |
| 108 | +int main (int argc, char** argv) |
| 109 | +{ |
| 110 | + using namespace dyad_residency; |
| 111 | + |
| 112 | + int seed = 0; |
| 113 | + Set_Type set_type = Set_LRU_; |
| 114 | + |
| 115 | + if (argc > 3) { |
| 116 | + return EXIT_FAILURE; |
| 117 | + } |
| 118 | + if (argc >= 2) { |
| 119 | + seed = atoi (argv[1]); |
| 120 | + } |
| 121 | + if (argc == 3) { |
| 122 | + int st = atoi (argv[2]); |
| 123 | + set_type = static_cast<Set_Type> (st % Set_End_); |
| 124 | + } |
| 125 | + |
| 126 | + typedef std::vector<std::string> access; |
| 127 | + access acc; // access pattern in terms of the block index |
| 128 | + acc.push_back ("1"); |
| 129 | + acc.push_back ("4"); |
| 130 | + acc.push_back ("2"); |
| 131 | + acc.push_back ("3"); |
| 132 | + acc.push_back ("5"); |
| 133 | + acc.push_back ("5"); |
| 134 | + acc.push_back ("3"); |
| 135 | + |
| 136 | + return cache_demo (set_type, seed, 4, 2, 8, 2, acc); |
| 137 | +} |
0 commit comments