├── .clang-format ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── Makefile ├── README.md ├── lib ├── .spec_factory.hpp.swp ├── contention_point.hpp ├── cost.hpp ├── cps │ ├── buggy_2l_rr_scheduler.hpp │ ├── leaf_spine.hpp │ ├── loom_mqprio.hpp │ ├── priority_scheduler.hpp │ ├── rr_scheduler.hpp │ └── tbf.hpp ├── example.hpp ├── input_only_solver.hpp ├── metric.hpp ├── metrics │ ├── aipg.hpp │ ├── cblocked.hpp │ ├── cdeq.hpp │ ├── cenq.hpp │ ├── deq.hpp │ ├── dst.hpp │ ├── ecmp.hpp │ └── qsize.hpp ├── net_context.hpp ├── params.hpp ├── qms │ ├── buggy_2l_rr_qm.hpp │ ├── leaf_forwarding_qm.hpp │ ├── loom_demux_qm.hpp │ ├── loom_flow_enq_qm.hpp │ ├── loom_nic_enq_qm.hpp │ ├── priority_qm.hpp │ ├── rr_qm.hpp │ ├── spine_forwarding_qm.hpp │ ├── switch_xbar_qm.hpp │ └── tbf_qm.hpp ├── query.hpp ├── queue.hpp ├── queuing_module.hpp ├── search.hpp ├── shared_config.hpp ├── solver.hpp ├── spec_factory.hpp ├── tests.hpp ├── util.hpp └── workload.hpp ├── scripts ├── perf.sh └── run.sh ├── src ├── contention_point.cpp ├── cost.cpp ├── cps │ ├── buggy_2l_rr_scheduler.cpp │ ├── leaf_spine.cpp │ ├── loom_mqprio.cpp │ ├── priority_scheduler.cpp │ ├── rr_scheduler.cpp │ └── tbf.cpp ├── example.cpp ├── input_only_solver.cpp ├── main.cpp ├── metric.cpp ├── metrics │ ├── aipg.cpp │ ├── cblocked.cpp │ ├── cdeq.cpp │ ├── cenq.cpp │ ├── deq.cpp │ ├── dst.cpp │ ├── ecmp.cpp │ └── qsize.cpp ├── net_context.cpp ├── qms │ ├── buggy_2l_rr_qm.cpp │ ├── leaf_forwarding_qm.cpp │ ├── loom_demux_qm.cpp │ ├── loom_flow_enq_qm.cpp │ ├── loom_nic_enq_qm.cpp │ ├── priority_qm.cpp │ ├── rr_qm.cpp │ ├── spine_forwarding_qm.cpp │ ├── switch_xbar_qm.cpp │ └── tbf_qm.cpp ├── query.cpp ├── queue.cpp ├── queuing_module.cpp ├── search.cpp ├── shared_config.cpp ├── solver.cpp ├── spec_factory.cpp ├── tests.cpp ├── util.cpp └── workload.cpp └── tests ├── main.cpp ├── rr_scheduler_test.cpp ├── rr_scheduler_test.hpp ├── search_test.cpp ├── search_test.hpp ├── simple_cp.cpp ├── simple_cp.hpp ├── tbf_test.cpp ├── tbf_test.hpp ├── test_class.hpp ├── test_runner.cpp └── test_runner.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | #Reference: https://clang.llvm.org/docs/ClangFormatStyleOptions.html 3 | Language: Cpp 4 | IndentWidth: 4 5 | TabWidth: 4 6 | PointerAlignment: Left 7 | AccessModifierOffset: -4 8 | Cpp11BracedListStyle: true 9 | BinPackArguments: false 10 | BinPackParameters: false 11 | ColumnLimit: 100 12 | SpaceBeforeCpp11BracedList: false 13 | ConstructorInitializerIndentWidth: 0 14 | PackConstructorInitializers: CurrentLine 15 | AllowShortIfStatementsOnASingleLine: WithoutElse 16 | BreakConstructorInitializers: AfterColon 17 | SpaceBeforeInheritanceColon: true 18 | SpaceBeforeCtorInitializerColon: false 19 | # 20 | AllowShortFunctionsOnASingleLine: None 21 | SpaceBeforeParens: Custom 22 | SpaceBeforeParensOptions: 23 | AfterOverloadedOperator: false 24 | SpaceAfterCStyleCast: true 25 | MaxEmptyLinesToKeep: 3 26 | PenaltyBreakAssignment: 200 27 | PenaltyBreakBeforeFirstCallParameter: 100 28 | AllowShortCaseLabelsOnASingleLine: true 29 | AlignAfterOpenBracket: Align 30 | IndentCaseLabels: true 31 | ... 32 | 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI Workflow 2 | on: [ push ] 3 | jobs: 4 | format: 5 | runs-on: self-hosted 6 | steps: 7 | - name: Checkout the repository 8 | uses: actions/checkout@v3 9 | - name: Check format 10 | run: make check-format 11 | build: 12 | runs-on: self-hosted 13 | needs: [ format ] 14 | steps: 15 | - name: Checkout the repository 16 | uses: actions/checkout@v3 17 | - name: Make 18 | run: make -j2 clean all build/fperf_test 19 | - name: Upload fperf executable 20 | uses: actions/upload-artifact@v3 21 | with: 22 | name: fperf 23 | path: build/fperf 24 | - name: Upload unit test executable 25 | uses: actions/upload-artifact@v3 26 | with: 27 | name: fperf_test 28 | path: build/fperf_test 29 | unit-test: 30 | runs-on: self-hosted 31 | needs: [ build ] 32 | steps: 33 | - name: Download test artifact 34 | uses: actions/download-artifact@v3 35 | with: 36 | name: fperf_test 37 | - name: Making test artifact executable 38 | run: chmod +x fperf_test 39 | - name: Run tests 40 | run: ./fperf_test 41 | e2e-test: 42 | runs-on: self-hosted 43 | needs: [ build, unit-test ] 44 | steps: 45 | - name: Download fperf artifact 46 | uses: actions/download-artifact@v3 47 | with: 48 | name: fperf 49 | - name: Making fperf artifact executable 50 | run: chmod +x fperf 51 | - name: Run the fperf 52 | run: ./fperf rr 53 | 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.log 3 | 4 | # For Windows/Visual Studio installations 5 | .vs/ 6 | x64/ 7 | fperf.* 8 | libz3.dll 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX := g++ 2 | CXXFLAGS := -pedantic-errors -Wno-sign-compare -Wno-unknown-pragmas -Wall -Wextra -Werror -std=c++17 -O3 3 | LDFLAGS := -L/usr/lib -L/usr/local/lib/ -lstdc++ -lm -lz3 4 | BUILD := ./build 5 | OBJ_DIR := $(BUILD)/objects 6 | APP_DIR := $(BUILD) 7 | TARGET := fperf 8 | INCLUDE := -I/usr/local/include -Ilib/ -Ilib/metrics/ -Ilib/cps -Ilib/qms 9 | SRC := $(wildcard src/*.cpp) \ 10 | $(wildcard src/*/*.cpp) 11 | TEST_SRC := $(wildcard tests/*.cpp) 12 | TEST_TARGET_PATH := $(APP_DIR)/$(TARGET)_test 13 | 14 | HEADERS := $(patsubst src/%.cpp,lib/%.hpp, $(filter-out src/main.cpp, $(SRC))) 15 | OBJECTS := $(SRC:%.cpp=$(OBJ_DIR)/%.o) 16 | 17 | all: build $(APP_DIR)/$(TARGET) 18 | 19 | $(OBJ_DIR)/%.o: %.cpp 20 | @mkdir -p $(@D) 21 | $(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@ 22 | 23 | $(APP_DIR)/$(TARGET): $(OBJECTS) 24 | @mkdir -p $(@D) 25 | $(CXX) $(CXXFLAGS) -o $(APP_DIR)/$(TARGET) $^ $(LDFLAGS) 26 | 27 | .PHONY: all build clean test check-format format 28 | 29 | build: 30 | @mkdir -p $(APP_DIR) 31 | @mkdir -p $(OBJ_DIR) 32 | 33 | run: 34 | ./$(APP_DIR)/$(TARGET) 35 | 36 | $(TEST_TARGET_PATH): $(OBJECTS) $(TEST_SRC) 37 | $(CXX) $(CXXFLAGS) $(INCLUDE) -o $@ $(TEST_SRC) $(filter-out ./build/objects/src/main.o, $(OBJECTS)) $(LDFLAGS) 38 | 39 | test: $(TEST_TARGET_PATH) 40 | $^ 41 | 42 | check-format: $(HEADERS) $(SRC) 43 | clang-format --dry-run -Werror $^ 44 | 45 | format: $(HEADERS) $(SRC) 46 | clang-format -i $^ 47 | 48 | clean: 49 | -@rm -rvf $(OBJ_DIR)/* 50 | -@rm -rvf $(APP_DIR)/* 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fperf 2 | 3 | [Formal Methods for Network Performance Analysis](https://mina.arashloo.net/docs/fperf.pdf), Mina Tahmasbi Arashloo, Ryan Beckett, Rachit Agarwal, NSDI'23 4 | 5 | 6 | 7 | The stand-alone priority schedulers, composition of schedulers, and throughput analysis on a leaf-spine topology. More to come soon! 8 | 9 | ## Installation 10 | fperf currently runs on Z3 v4.8.11 [link](https://github.com/Z3Prover/z3/releases/tag/z3-4.8.11) 11 | 12 | ### Windows with Visual Studio 13 | 1. Download fperf through github 14 | 2. Create a new project in Visual Studio in the fperf folder 15 | 3. Download Z3 for windows [here](https://github.com/Z3Prover/z3/releases/tag/z3-4.8.11) 16 | 4. Build Z3 with the instructions from [here](https://github.com/exercism/z3/blob/main/docs/INSTALLATION.md) under **Building Z3 on Windows using Visual Studio Command Prompt** 17 | 5. Go to "Project" -> "Properties" and in the General tab and perform the following: 18 | - Set "Platform Toolset" to "LLVM" 19 | - Set "C++ Language Standard" to "C++ 17 Standard" 20 | 6. Under the same "Configuration Properties" page, go to "C/C++" -> "General" -> "Include Additional Directories" and add the following: 21 | - `[path to z3]\z3\src\api` 22 | - `[path to z3]\z3\src\api\c++`
23 | The following may be required if Visual Studio doesn't recognize the subfolders of fperf 24 | - `[path to fperf]\fperf\src\qms` 25 | - `[path to fperf]\fperf\src\metrics` 26 | - `[path to fperf]\fperf\src\cps` 27 | - `[path to fperf]\fperf\src` 28 | - `[path to fperf]\fperf\lib\cps` 29 | - `[path to fperf]\fperf\lib\metrics` 30 | - `[path to fperf]\fperf\lib\qms` 31 | - `[path to fperf]\fperf\lib` 32 | 7. Under "Linker" -> "General" -> "Include Additional Directories", add `[path to z3]\z3\build\` 33 | 8. Under "Linker" -> "Input", add `[path to z3]\z3\build\libz3.lib` 34 | 9. Press the green arrow in the top bar of Visual Studio to run fperf 35 | -------------------------------------------------------------------------------- /lib/.spec_factory.hpp.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/all-things-networking/fperf/ec3f914929f4e6456ea87a4103239a3520820371/lib/.spec_factory.hpp.swp -------------------------------------------------------------------------------- /lib/contention_point.hpp: -------------------------------------------------------------------------------- 1 | // contention_point.hpp 2 | // FPerf 3 | // 4 | // Created by Mina Tahmasbi Arashloo on 11/12/20. 5 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 6 | // 7 | 8 | #ifndef contention_point_hpp 9 | #define contention_point_hpp 10 | 11 | #include 12 | #include 13 | 14 | #include "metric.hpp" 15 | #include "query.hpp" 16 | #include "queue.hpp" 17 | #include "queuing_module.hpp" 18 | #include "shared_config.hpp" 19 | #include "solver.hpp" 20 | #include "util.hpp" 21 | 22 | using namespace std; 23 | 24 | class ContentionPoint : public Solver { 25 | public: 26 | ContentionPoint(unsigned int total_time); 27 | 28 | void set_base_workload(Workload wl); 29 | Workload get_base_workload(); 30 | expr get_base_wl_expr(); 31 | 32 | void set_query(Query& query); 33 | unsigned int in_queue_cnt(); 34 | vector get_in_queues(); 35 | unsigned int get_total_time(); 36 | 37 | unsigned int out_queue_cnt(); 38 | Queue* get_out_queue(unsigned int ind); 39 | 40 | Query get_query(); 41 | bool is_query_set(); 42 | 43 | QueuingModule* get_qm(cid_t id); 44 | 45 | bool set_shared_config(SharedConfig* shared_config); 46 | bool is_shared_config_set(); 47 | 48 | solver_res_t solve(); 49 | solver_res_t satisfy_query(); 50 | solver_res_t check_workload_without_query(Workload wl); 51 | solver_res_t check_workload_with_query(Workload wl, IndexedExample* eg); 52 | 53 | bool generate_base_example(IndexedExample* eg, qset_t& target_queues, unsigned int max_queue); 54 | 55 | void generate_good_examples(IndexedExample* base_eg, 56 | unsigned int count, 57 | deque& examples); 58 | 59 | void generate_bad_examples(unsigned int count, deque& examples); 60 | 61 | void generate_good_examples_flow(deque& examples, unsigned int count); 62 | 63 | void generate_good_examples2(IndexedExample* base_eg, 64 | unsigned int count, 65 | deque& examples); 66 | 67 | 68 | 69 | void generate_good_examples_from_base_flow(deque& examples, 70 | unsigned int count, 71 | IndexedExample* base_eg, 72 | qset_t non_zero_queues); 73 | 74 | IndexedExample* index_example(Example* eg); 75 | Example* unindex_example(IndexedExample* ieg); 76 | 77 | bool workload_satisfies_example(Workload wl, IndexedExample* eg); 78 | double workload_example_match(Workload wl, IndexedExample* eg); 79 | 80 | string stats_str(); 81 | 82 | friend ostream& operator<<(ostream& os, const ContentionPoint& p); 83 | 84 | protected: 85 | NetContext net_ctx; 86 | solver* z3_solver; 87 | optimize* z3_optimizer; 88 | map constr_map; 89 | 90 | unsigned int total_time; 91 | 92 | vector nodes; 93 | map> module_edges; 94 | map> queue_edges; 95 | map id_to_qm; 96 | map id_to_ioq; 97 | 98 | vector in_queues; 99 | vector out_queues; 100 | map> metrics; 101 | 102 | void init(); 103 | 104 | private: 105 | Workload base_wl; 106 | expr base_wl_expr; 107 | 108 | Query query; 109 | expr query_expr; 110 | bool query_is_set = false; 111 | 112 | Dists* dists = NULL; 113 | SharedConfig* shared_config = NULL; 114 | qset_t target_queues; 115 | bool shared_config_is_set = false; 116 | 117 | 118 | virtual void add_nodes() = 0; 119 | virtual void add_edges() = 0; 120 | virtual void add_metrics() = 0; 121 | 122 | void setup_edges(); 123 | void populate_id_to_ioq(); 124 | void populate_in_queues(); 125 | void populate_out_queues(); 126 | 127 | void add_node_constrs(); 128 | void add_metric_constrs(); 129 | void add_in_queue_constrs(); 130 | void add_out_queue_constrs(); 131 | 132 | void add_constr(expr const& e, char const* p); 133 | void add_constr_from_map(map constr_map); 134 | 135 | string get_model_str(model& m); 136 | virtual string cp_model_str(model& m, NetContext& net_ctx, unsigned int t) = 0; 137 | void populate_example_from_model(model& m, IndexedExample* eg); 138 | 139 | expr get_random_eg_mod(IndexedExample* eg, unsigned int mod_cnt, qset_t queue_set); 140 | solver_res_t get_solver_res_t(check_result z3_res); 141 | 142 | 143 | // generate expressions from workloads and queries 144 | expr get_expr(Query& query); 145 | expr get_expr(IndexedExample* eg, vector& metrics); 146 | expr get_expr(IndexedExample* eg); 147 | expr get_expr(Workload wl); 148 | expr get_expr(TimedSpec tspec); 149 | expr get_expr(Unique uniq, time_range_t time_range); 150 | expr get_expr(Same same, time_range_t time_range); 151 | expr get_expr(Incr incr, time_range_t time_range); 152 | expr get_expr(Decr decr, time_range_t time_range); 153 | expr get_expr(Comp comp, time_range_t time_range); 154 | expr get_expr(Comp comp, unsigned int t); 155 | m_val_expr_t get_expr(Expr* rhs, unsigned int t); 156 | m_val_expr_t get_expr(MExpr* lhs, unsigned int t); 157 | m_val_expr_t get_expr(Constant c, unsigned int t); 158 | m_val_expr_t get_expr(Time time, unsigned int t); 159 | m_val_expr_t get_expr(Indiv indiv, unsigned int t); 160 | m_val_expr_t get_expr(QSum qsum, unsigned int t); 161 | 162 | expr mk_op(expr lhs, Op op, expr rhs); 163 | 164 | /* *********** Workload Satisifes Example ************ */ 165 | bool timedspec_satisfies_example(TimedSpec spec, IndexedExample* eg); 166 | bool eval_spec(Unique uniq, IndexedExample* eg, time_range_t time_range) const; 167 | bool eval_spec(Same same, IndexedExample* eg, time_range_t time_range) const; 168 | bool eval_spec(Incr incr, IndexedExample* eg, time_range_t time_range) const; 169 | bool eval_spec(Decr decr, IndexedExample* eg, time_range_t time_range) const; 170 | bool eval_spec(Comp comp, IndexedExample* eg, time_range_t time_range) const; 171 | void eval_rhs(Expr* rhs, IndexedExample* eg, unsigned int time, metric_val& res) const; 172 | void eval_m_expr(MExpr* m_expr, IndexedExample* eg, unsigned int time, metric_val& res) const; 173 | void eval_m_expr(QSum tsum, IndexedExample* eg, unsigned int time, metric_val& res) const; 174 | void eval_m_expr(Indiv tone, IndexedExample* eg, unsigned int time, metric_val& res) const; 175 | void eval_Time(Time time, IndexedExample* eg, unsigned int t, metric_val& res) const; 176 | }; 177 | 178 | #endif /* contention_point_hpp */ 179 | -------------------------------------------------------------------------------- /lib/cost.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // cost.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/28/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef cost_hpp 10 | #define cost_hpp 11 | 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | typedef unsigned int wl_cost_t; 18 | typedef pair cost_t; 19 | 20 | unsigned int uint_val(const wl_cost_t cost); 21 | unsigned int uint_val(const cost_t cost); 22 | 23 | int operator-(const cost_t cost1, const cost_t cost2); 24 | 25 | bool operator<(const cost_t cost1, const cost_t cost2); 26 | bool operator<=(const cost_t cost1, const cost_t cost2); 27 | bool operator>(const cost_t cost1, const cost_t cost2); 28 | bool operator>=(const cost_t cost1, const cost_t cost2); 29 | bool operator==(const cost_t cost1, const cost_t cost2); 30 | bool operator!=(const cost_t cost1, const cost_t cost2); 31 | 32 | #endif /* cost_hpp */ 33 | -------------------------------------------------------------------------------- /lib/cps/buggy_2l_rr_scheduler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // buggy_2l_rr_scheduler.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 08/03/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef buggy_2l_rr_scheduler_hpp 10 | #define buggy_2l_rr_scheduler_hpp 11 | 12 | #include "aipg.hpp" 13 | #include "cdeq.hpp" 14 | #include "cenq.hpp" 15 | #include "contention_point.hpp" 16 | 17 | using namespace std; 18 | 19 | class Buggy2LRRScheduler : public ContentionPoint { 20 | public: 21 | Buggy2LRRScheduler(unsigned int queue_cnt, unsigned int total_time); 22 | 23 | private: 24 | unsigned int queue_cnt; 25 | vector cenq; 26 | vector cdeq; 27 | vector aipg; 28 | 29 | void add_nodes(); 30 | void add_edges(); 31 | void add_metrics(); 32 | 33 | string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 34 | }; 35 | 36 | #endif /* buggy_2l_rr_scheduler_hpp */ 37 | -------------------------------------------------------------------------------- /lib/cps/leaf_spine.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // leaf_spine.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/24/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef leaf_spine_hpp 10 | #define leaf_spine_hpp 11 | 12 | #include "aipg.hpp" 13 | #include "cenq.hpp" 14 | #include "contention_point.hpp" 15 | #include "dst.hpp" 16 | #include "ecmp.hpp" 17 | #include "qsize.hpp" 18 | 19 | using namespace std; 20 | 21 | class LeafSpine : public ContentionPoint { 22 | public: 23 | LeafSpine(unsigned int leaf_cnt, 24 | unsigned int spine_cnt, 25 | unsigned int servers_per_leaf, 26 | unsigned int total_time, 27 | bool reduce_queues); 28 | 29 | private: 30 | unsigned int leaf_cnt; 31 | unsigned int spine_cnt; 32 | unsigned int servers_per_leaf; 33 | unsigned int leaf_port_cnt; 34 | unsigned int spine_port_cnt; 35 | unsigned int server_cnt; 36 | bool reduce_queues; 37 | 38 | vector cenq; 39 | vector aipg; 40 | vector dst; 41 | vector ecmp; 42 | vector qsize; 43 | 44 | vector leaf_voq_input_map; 45 | vector leaf_voq_output_map; 46 | vector spine_voq_input_map; 47 | vector spine_voq_output_map; 48 | 49 | void add_nodes(); 50 | void add_edges(); 51 | void add_metrics(); 52 | 53 | string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 54 | }; 55 | 56 | 57 | #endif /* leaf_spine_hpp */ 58 | -------------------------------------------------------------------------------- /lib/cps/loom_mqprio.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_mqprio.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef loom_mqprio_hpp 10 | #define loom_mqprio_hpp 11 | 12 | #include "aipg.hpp" 13 | #include "cenq.hpp" 14 | #include "contention_point.hpp" 15 | 16 | using namespace std; 17 | 18 | class LoomMQPrio : public ContentionPoint { 19 | public: 20 | LoomMQPrio(unsigned int nic_tx_queue_cnt, 21 | unsigned int per_core_flow_cnt, 22 | unsigned int total_time); 23 | 24 | private: 25 | unsigned int nic_tx_queue_cnt; 26 | unsigned int per_core_flow_cnt; 27 | unsigned int tenant_cnt = 2; 28 | 29 | vector cenq; 30 | vector aipg; 31 | 32 | void add_nodes(); 33 | void add_edges(); 34 | void add_metrics(); 35 | 36 | string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 37 | }; 38 | 39 | 40 | #endif /* loom_mqprio_hpp */ 41 | -------------------------------------------------------------------------------- /lib/cps/priority_scheduler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // priority_scheduler.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/16/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef priority_scheduler_hpp 10 | #define priority_scheduler_hpp 11 | 12 | #include "aipg.hpp" 13 | #include "cblocked.hpp" 14 | #include "cenq.hpp" 15 | #include "contention_point.hpp" 16 | 17 | using namespace std; 18 | 19 | class PrioScheduler : public ContentionPoint { 20 | public: 21 | PrioScheduler(unsigned int prio_levels, unsigned int total_time); 22 | 23 | private: 24 | unsigned int prio_levels; 25 | vector cblocked; 26 | vector cenq; 27 | vector aipg; 28 | 29 | void add_nodes(); 30 | void add_edges(); 31 | void add_metrics(); 32 | 33 | string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 34 | }; 35 | 36 | #endif /* priority_scheduler_hpp */ 37 | -------------------------------------------------------------------------------- /lib/cps/rr_scheduler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // rr_scheduler.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/18/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef rr_scheduler_hpp 10 | #define rr_scheduler_hpp 11 | 12 | #include "aipg.hpp" 13 | #include "cdeq.hpp" 14 | #include "cenq.hpp" 15 | #include "contention_point.hpp" 16 | #include "qsize.hpp" 17 | 18 | using namespace std; 19 | 20 | class RRScheduler : public ContentionPoint { 21 | public: 22 | RRScheduler(unsigned int queue_cnt, unsigned int total_time); 23 | 24 | private: 25 | unsigned int queue_cnt; 26 | vector cenq; 27 | vector cdeq; 28 | vector aipg; 29 | 30 | void add_nodes(); 31 | void add_edges(); 32 | void add_metrics(); 33 | 34 | string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 35 | }; 36 | 37 | #endif /* rr_scheduler_hpp */ 38 | -------------------------------------------------------------------------------- /lib/cps/tbf.hpp: -------------------------------------------------------------------------------- 1 | #include "cdeq.hpp" 2 | #include "cenq.hpp" 3 | #include "contention_point.hpp" 4 | #include "deq.hpp" 5 | #include "qsize.hpp" 6 | #include "tbf_qm.hpp" 7 | 8 | class TBF : public ContentionPoint { 9 | public: 10 | TBF(unsigned int total_time, TBFInfo info); 11 | Queue* get_in_queue(); 12 | Queue* get_out_queue(); 13 | 14 | private: 15 | std::vector cenq; 16 | std::vector cdeq; 17 | std::vector deq; 18 | 19 | void add_nodes(); 20 | void add_edges(); 21 | void add_metrics(); 22 | 23 | TBFQM* qm; 24 | TBFInfo info; 25 | 26 | virtual std::string cp_model_str(model& m, NetContext& net_ctx, unsigned int t); 27 | }; 28 | -------------------------------------------------------------------------------- /lib/example.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // example.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/15/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef example_hpp 10 | #define example_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "util.hpp" 18 | 19 | using namespace std; 20 | 21 | struct Example { 22 | unsigned int total_time; 23 | cid_t query_qid; 24 | map> enqs; 25 | map> deqs; 26 | 27 | map>> enqs_meta1; 28 | map>> enqs_meta2; 29 | 30 | friend ostream& operator<<(ostream& os, const Example& eg); 31 | }; 32 | 33 | struct IndexedExample { 34 | unsigned int total_time; 35 | cid_t query_qid; 36 | vector> enqs; 37 | vector> deqs; 38 | vector>> enqs_meta1; 39 | vector>> enqs_meta2; 40 | 41 | friend ostream& operator<<(ostream& os, const IndexedExample& eg); 42 | }; 43 | 44 | struct Trace { 45 | unsigned int total_time; 46 | vector> enqs; 47 | 48 | friend ostream& operator<<(ostream& os, const Trace& tr); 49 | }; 50 | 51 | void write_examples_to_file(deque& examples, string fname); 52 | 53 | void read_examples_from_file(deque& examples, string fname); 54 | 55 | #endif /* example_hpp */ 56 | -------------------------------------------------------------------------------- /lib/input_only_solver.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // input_only_solver.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/10/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef input_only_solver_hpp 10 | #define input_only_solver_hpp 11 | 12 | #include "solver.hpp" 13 | 14 | class InputOnlySolver : Solver { 15 | public: 16 | InputOnlySolver(){}; 17 | 18 | solver_res_t check_workload_without_query(Workload wl); 19 | solver_res_t check_workload_with_query(Workload wl, IndexedExample* eg); 20 | }; 21 | 22 | #endif /* input_only_solver_hpp */ 23 | -------------------------------------------------------------------------------- /lib/metric.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // metric.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/17/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef metric_hpp 10 | #define metric_hpp 11 | 12 | #include 13 | 14 | #include "example.hpp" 15 | #include "net_context.hpp" 16 | #include "queue.hpp" 17 | #include "util.hpp" 18 | 19 | class Queue; 20 | 21 | enum class metric_t { CENQ = 0, AIPG, DST, ECMP, QSIZE, CDEQ, CBLOCKED, DEQ }; 22 | 23 | enum class metric_granularity_t { PACKET = 0, TIMESTEP }; 24 | 25 | struct metric_properties { 26 | bool non_negative; // Used in normalization to distinguish zero and non-zero comparisons 27 | bool non_decreasing; // Used in normalization to extend time range to 0 or T 28 | bool aggregatable; 29 | }; 30 | 31 | struct metric_val { 32 | bool valid = false; 33 | unsigned int value; 34 | }; 35 | 36 | typedef pair m_val_expr_t; 37 | 38 | class Metric { 39 | public: 40 | static const map properties; 41 | 42 | Metric(metric_t m, Queue* queue, unsigned int total_time, NetContext& net_ctx); 43 | 44 | m_val_expr_t val(unsigned int ind); 45 | virtual void 46 | eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) = 0; 47 | 48 | virtual void populate_val_exprs(NetContext& net_ctx) = 0; 49 | 50 | cid_t get_id(); 51 | metric_t get_type(); 52 | 53 | protected: 54 | cid_t id; 55 | metric_t m_type; 56 | 57 | Queue* queue; 58 | unsigned int total_time; 59 | vector value_; 60 | vector valid_; 61 | 62 | void init(NetContext& net_ctx); 63 | }; 64 | 65 | ostream& operator<<(ostream& os, const metric_t& metric); 66 | 67 | #endif /* metric_hpp */ 68 | -------------------------------------------------------------------------------- /lib/metrics/aipg.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // aipg.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 8/5/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef aipg_hpp 10 | #define aipg_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class AIPG : public Metric { 16 | public: 17 | AIPG(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | 25 | #endif /* aipg_hpp */ 26 | -------------------------------------------------------------------------------- /lib/metrics/cblocked.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // cblocked.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/17/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef cblocked_hpp 10 | #define cblocked_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class CBlocked : public Metric { 16 | public: 17 | CBlocked(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* cblocked_hpp */ 25 | -------------------------------------------------------------------------------- /lib/metrics/cdeq.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // cdeq.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/19/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef cdeq_hpp 10 | #define cdeq_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class CDeq : public Metric { 16 | public: 17 | CDeq(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* cdeq_hpp */ 25 | -------------------------------------------------------------------------------- /lib/metrics/cenq.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // cenq.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/11/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef cenq_hpp 10 | #define cenq_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class CEnq : public Metric { 16 | public: 17 | CEnq(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* cenq_hpp */ 25 | -------------------------------------------------------------------------------- /lib/metrics/deq.hpp: -------------------------------------------------------------------------------- 1 | #ifndef METRICS_ENQ_HPP 2 | #define METRICS_ENQ_HPP 3 | 4 | #include "metric.hpp" 5 | 6 | class Deq : public Metric { 7 | public: 8 | Deq(Queue* queue, unsigned int total_time, NetContext& net_ctx); 9 | 10 | void populate_val_exprs(NetContext& net_ctx); 11 | 12 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /lib/metrics/dst.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // dst.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 06/06/23. 6 | // Copyright © 2023 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef dst_hpp 10 | #define dst_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class Dst : public Metric { 16 | public: 17 | Dst(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* dst_hpp */ 25 | -------------------------------------------------------------------------------- /lib/metrics/ecmp.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // ecmp.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 06/06/23. 6 | // Copyright © 2023 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef ecmp_hpp 10 | #define ecmp_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class Ecmp : public Metric { 16 | public: 17 | Ecmp(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* ecmp_hpp */ 25 | -------------------------------------------------------------------------------- /lib/metrics/qsize.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // qsize.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/19/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef qsize_hpp 10 | #define qsize_hpp 11 | 12 | #include "metric.hpp" 13 | #include "queue.hpp" 14 | 15 | class QSize : public Metric { 16 | public: 17 | QSize(Queue* queue, unsigned int total_time, NetContext& net_ctx); 18 | 19 | void populate_val_exprs(NetContext& net_ctx); 20 | 21 | void eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res); 22 | }; 23 | 24 | #endif /* qsize_hpp */ 25 | -------------------------------------------------------------------------------- /lib/net_context.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // NetContext.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 4/2/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef NetContext_hpp 10 | #define NetContext_hpp 11 | 12 | #pragma clang diagnostic push 13 | #pragma clang diagnostic ignored "-Wdocumentation" 14 | 15 | #include "z3++.h" 16 | 17 | #pragma clang diagnostic pop 18 | 19 | using namespace z3; 20 | 21 | class NetContext { 22 | public: 23 | NetContext(); 24 | 25 | expr pkt_const(char const* name); 26 | expr pkt2val(expr pkt); 27 | expr pkt2meta1(expr pkt); 28 | expr pkt2meta2(expr pkt); 29 | 30 | expr pkt_val(bool val, int meta1, int meta2); 31 | 32 | expr null_pkt(); 33 | 34 | expr int_const(char* name); 35 | expr int_val(int n); 36 | 37 | expr bool_const(char* name); 38 | expr bool_val(bool b); 39 | 40 | context& z3_ctx(); 41 | 42 | unsigned long get_bool_var_cnt(); 43 | unsigned long get_int_var_cnt(); 44 | 45 | private: 46 | context ctx; 47 | // Packets 48 | const char* names[3] = {"val", "meta1", "meta2"}; 49 | z3::sort sorts[3] = {ctx.bool_sort(), ctx.int_sort(), ctx.int_sort()}; 50 | func_decl_vector* ptup_projs = new func_decl_vector(ctx); 51 | func_decl pkt_sort = ctx.tuple_sort("pkt_tuple", 3, names, sorts, *ptup_projs); 52 | func_decl ptup = pkt_sort; 53 | 54 | 55 | const unsigned int VAL_IND = 0; 56 | const unsigned int META1_IND = 1; 57 | const unsigned int META2_IND = 2; 58 | 59 | /* ********* Stats ********** */ 60 | unsigned long bool_var_cnt = 0; 61 | unsigned long int_var_cnt = 0; 62 | }; 63 | 64 | #endif /* NetContext_hpp */ 65 | -------------------------------------------------------------------------------- /lib/params.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // params.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/5/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef params_hpp 10 | #define params_hpp 11 | 12 | #include 13 | 14 | using namespace std; 15 | 16 | const unsigned int TOTAL_TIME = 10; 17 | const unsigned int MAX_ENQ = 4; 18 | const unsigned int MAX_QUEUE_SIZE = 10; 19 | 20 | const unsigned int UNDEFINED_METRIC_VAL = 31; 21 | 22 | const unsigned int GOOD_EXAMPLE_WEIGHT = 1; 23 | const unsigned int BAD_EXAMPLE_WEIGHT = 2; 24 | const unsigned int EXAMPLE_WEIGHT_IN_COST = 10; 25 | const unsigned int SPEC_CNT_WEIGHT = 2; 26 | const unsigned int NUM_QUEUES_WITH_SPECS_WEIGHT = 2; 27 | const unsigned int MAX_SPEC_CNT_PER_QUEUE_WEIGHT = 1; 28 | const unsigned int AVG_SPEC_CNT_OVER_QUEUES = 1; 29 | const unsigned int AVG_TIME_RANGE_OVER_SPECS_WEIGHT = 1; 30 | 31 | const unsigned int Z3_RANDOM_SEED = 100; 32 | const unsigned int MAX_SPEC = 6; 33 | const unsigned int LOCAL_SEARCH_THRESH = 10; 34 | const unsigned int RESET_THRESH_SLOW_PROGRESS = 20; 35 | const unsigned int RESET_THRESH_BACKTRACK = 10; 36 | const unsigned int LOCAL_SEARCH_MAX_HOPS = 3; 37 | //TODO: set it in terms of other parameters? 38 | //const unsigned int NEGLIGIBLE_PROGRESS = (5 * (BAD_EXAMPLE_WEIGHT) * EXAMPLE_WEIGHT_IN_COST); 39 | const double NEGLIGIBLE_PROGRESS_FRAC = 0.003; 40 | const unsigned int MIN_CANDIDATES = 5; 41 | const unsigned int MAX_CANDIDATES = 1000; 42 | extern unsigned long MAX_COST; 43 | const double COST_LAMBDA = 1.0; 44 | const unsigned int TIME_RANGE_NEI_CNT = 5; 45 | const unsigned int RANDOM_ADD_CNT = 5; 46 | const unsigned int SOLUTION_REFINEMENT_MAX_ROUNDS = 0; 47 | 48 | 49 | const double EG_RANDOM_MOD_PERCENT = 0.2; 50 | const unsigned int EG_RANDOM_MOD_START = 10; 51 | const unsigned int EG_RANDOM_MOD_MAX_TRIES = 2; 52 | 53 | 54 | const vector DEFAULT_RHS_SELECTION_WEIGHTS{1, 1, 1}; 55 | const unsigned int DEFAULT_RHS_CONST_MIN = 0; 56 | const unsigned int DEFAULT_RHS_CONST_MAX = 3; 57 | const unsigned int DEFAULT_RHS_TIME_COEFF_MIN = 1; 58 | // TODO: if this is too large, it could cause inputs that flood the queues 59 | const unsigned int DEFAULT_RHS_TIME_COEFF_MAX = TOTAL_TIME; 60 | 61 | const vector DEFAULT_TRF_SELECTION_WEIGHTS{1, 1}; 62 | const vector DEFAULT_WL_METRIC_SELECTION_WEIGHTS{1, 1, 1, 1}; 63 | 64 | const unsigned int DEFAULT_COMP_RANGE_MIN = 0; 65 | const unsigned int DEFAULT_COMP_RANGE_MAX = 4; 66 | 67 | const unsigned int DEFAULT_ENQ_RANGE_MIN = 1; 68 | const unsigned int DEFAULT_ENQ_RANGE_MAX = MAX_ENQ; 69 | 70 | const unsigned int DEFAULT_RANDOM_SEED = 1680979592; 71 | 72 | #endif /* params_hpp */ 73 | -------------------------------------------------------------------------------- /lib/qms/buggy_2l_rr_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // 2l_rr_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 7/172l/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef buggy_2l_rr_qm_hpp 10 | #define buggy_2l_rr_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | using namespace std; 15 | 16 | class Buggy2LRRQM : public QueuingModule { 17 | public: 18 | Buggy2LRRQM(cid_t id, 19 | unsigned int total_time, 20 | vector in_queue_info, 21 | QueueInfo out_queue_info, 22 | NetContext& net_ctx); 23 | 24 | void add_constrs(NetContext& net_ctx, map& constr_map); 25 | 26 | Queue* new_fifo(); 27 | Queue* old_fifo(); 28 | expr inactive(unsigned int q, unsigned int t); 29 | 30 | private: 31 | Queue* new_queues; 32 | Queue* old_queues; 33 | vector* inactive_; 34 | 35 | void add_proc_vars(NetContext& net_ctx); 36 | }; 37 | 38 | #endif /* buggy_2l_rr_qm_hpp */ 39 | -------------------------------------------------------------------------------- /lib/qms/leaf_forwarding_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // leaf_forwarding_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/23/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef leaf_forwarding_qm_hpp 10 | #define leaf_forwarding_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | #include 14 | 15 | using namespace std; 16 | 17 | class LeafForwardingQM : public QueuingModule { 18 | public: 19 | LeafForwardingQM(cid_t id, 20 | unsigned int total_time, 21 | unsigned int leaf_id, 22 | unsigned int fw_id, 23 | unsigned int servers_per_leaf, 24 | unsigned int server_cnt, 25 | unsigned int spine_cnt, 26 | map output_voq_map, 27 | QueueInfo in_queue_info, 28 | vector out_queue_info, 29 | NetContext& net_ctx); 30 | 31 | void add_constrs(NetContext& net_ctx, map& constr_map); 32 | 33 | 34 | private: 35 | unsigned int leaf_id; 36 | unsigned int fw_id; 37 | unsigned int servers_per_leaf; 38 | unsigned int server_cnt; 39 | unsigned int spine_cnt; 40 | map output_voq_map; 41 | 42 | void add_proc_vars(NetContext& net_ctx); 43 | }; 44 | 45 | #endif /* leaf_forwarding_qm_hpp */ 46 | -------------------------------------------------------------------------------- /lib/qms/loom_demux_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_demux_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/4/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef loom_demux_qm_hpp 10 | #define loom_demux_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | class LoomDemuxQM : public QueuingModule { 15 | public: 16 | LoomDemuxQM(cid_t id, 17 | unsigned int total_time, 18 | QueueInfo in_queue_info, 19 | QueueInfo out_queue_info1, 20 | QueueInfo out_queue_info2, 21 | NetContext& net_ctx); 22 | 23 | void add_constrs(NetContext& net_ctx, map& constr_map); 24 | 25 | 26 | private: 27 | void add_proc_vars(NetContext& net_ctx); 28 | }; 29 | 30 | #endif /* loom_demux_qm_hpp */ 31 | -------------------------------------------------------------------------------- /lib/qms/loom_flow_enq_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_flow_enq_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef loom_flow_enq_qm_hpp 10 | #define loom_flow_enq_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | class LoomFlowEnqQM : public QueuingModule { 15 | public: 16 | LoomFlowEnqQM(cid_t id, 17 | unsigned int total_time, 18 | vector in_queue_info, 19 | QueueInfo out_queue_info1, 20 | QueueInfo out_queue_info2, 21 | NetContext& net_ctx); 22 | 23 | void add_constrs(NetContext& net_ctx, map& constr_map); 24 | 25 | 26 | private: 27 | void add_proc_vars(NetContext& net_ctx); 28 | void constrs_if_not_taken(NetContext& net_ctx, map& constr_map); 29 | }; 30 | 31 | 32 | #endif /* loom_flow_enq_qm_hpp */ 33 | -------------------------------------------------------------------------------- /lib/qms/loom_nic_enq_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_nic_enq_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef loom_nic_enq_qm_hpp 10 | #define loom_nic_enq_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | class LoomNICEnqQM : public QueuingModule { 15 | public: 16 | LoomNICEnqQM(cid_t id, 17 | unsigned int total_time, 18 | vector in_queue_info, 19 | QueueInfo out_queue_info1, 20 | QueueInfo out_queue_info2, 21 | NetContext& net_ctx); 22 | 23 | void add_constrs(NetContext& net_ctx, map& constr_map); 24 | 25 | 26 | private: 27 | unsigned int per_queue_share; 28 | void add_proc_vars(NetContext& net_ctx); 29 | 30 | void constrs_if_not_taken(NetContext& net_ctx, map& constr_map); 31 | }; 32 | 33 | 34 | #endif /* loom_nic_enq_qm_hpp */ 35 | -------------------------------------------------------------------------------- /lib/qms/priority_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // priority_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/12/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef priority_qm_hpp 10 | #define priority_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | class PriorityQM : public QueuingModule { 15 | public: 16 | PriorityQM(cid_t id, 17 | unsigned int total_time, 18 | vector in_queue_info, 19 | QueueInfo out_queue_info, 20 | NetContext& net_ctx); 21 | 22 | void add_constrs(NetContext& net_ctx, map& constr_map); 23 | 24 | 25 | private: 26 | void add_proc_vars(NetContext& net_ctx); 27 | }; 28 | 29 | #endif /* priority_qm_hpp */ 30 | -------------------------------------------------------------------------------- /lib/qms/rr_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // rr_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/17/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef rr_qm_hpp 10 | #define rr_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | class RRQM : public QueuingModule { 15 | public: 16 | RRQM(cid_t id, 17 | unsigned int total_time, 18 | vector in_queue_info, 19 | QueueInfo out_queue_info, 20 | NetContext& net_ctx); 21 | 22 | void add_constrs(NetContext& net_ctx, map& constr_map); 23 | 24 | expr last_served_queue(unsigned int q, unsigned int t); 25 | 26 | private: 27 | vector* last_served_queue_; 28 | void add_proc_vars(NetContext& net_ctx); 29 | }; 30 | 31 | #endif /* rr_qm_hpp */ 32 | -------------------------------------------------------------------------------- /lib/qms/spine_forwarding_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // spine_forwarding_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/23/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef spine_forwarding_qm_hpp 10 | #define spine_forwarding_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | #include 14 | 15 | using namespace std; 16 | 17 | class SpineForwardingQM : public QueuingModule { 18 | public: 19 | SpineForwardingQM(cid_t id, 20 | unsigned int total_time, 21 | unsigned int spine_id, 22 | unsigned int leaf_cnt, 23 | unsigned int servers_per_leaf, 24 | map output_voq_map, 25 | QueueInfo in_queue_info, 26 | vector out_queue_info, 27 | NetContext& net_ctx); 28 | 29 | void add_constrs(NetContext& net_ctx, map& constr_map); 30 | 31 | 32 | private: 33 | unsigned int spine_id; 34 | unsigned int leaf_cnt; 35 | unsigned int servers_per_leaf; 36 | map output_voq_map; 37 | 38 | void add_proc_vars(NetContext& net_ctx); 39 | }; 40 | 41 | #endif /* spine_forwarding_qm_hpp */ 42 | -------------------------------------------------------------------------------- /lib/qms/switch_xbar_qm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // switch_xbar_qm.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/13/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef switch_xbar_qm_hpp 10 | #define switch_xbar_qm_hpp 11 | 12 | #include "queuing_module.hpp" 13 | 14 | using namespace std; 15 | 16 | class SwitchXBarQM : public QueuingModule { 17 | public: 18 | SwitchXBarQM(cid_t id, 19 | unsigned int total_time, 20 | vector voq_input_map, 21 | vector voq_output_map, 22 | vector in_queue_info, 23 | vector out_queue_info, 24 | NetContext& net_ctx); 25 | 26 | virtual void add_constrs(NetContext& net_ctx, map& constr_map); 27 | 28 | bool connected(unsigned int in_port, unsigned int out_port); 29 | expr in_to_out(unsigned int in_port, unsigned int out_port, unsigned int t); 30 | expr out_from_in(unsigned int out_port, unsigned int in_port, unsigned int t); 31 | expr in_prio_head(unsigned int in_port, unsigned int out_port, unsigned int t); 32 | expr out_prio_head(unsigned int out_port, unsigned int in_port, unsigned int t); 33 | 34 | protected: 35 | vector voq_input_map; 36 | vector voq_output_map; 37 | unsigned int port_cnt; 38 | 39 | vector>* in_to_out_; 40 | vector>* out_from_in_; 41 | 42 | vector>* in_prio_head_; 43 | vector>* out_prio_head_; 44 | 45 | map> input_voq_map; 46 | map> output_voq_map; 47 | 48 | void add_proc_vars(NetContext& net_ctx); 49 | }; 50 | 51 | /* ********** LeafXBar ************ */ 52 | 53 | class LeafXBarQM : public SwitchXBarQM { 54 | public: 55 | LeafXBarQM(cid_t id, 56 | unsigned int leaf_id, 57 | unsigned int servers_per_leaf, 58 | unsigned int spine_cnt, 59 | unsigned int total_time, 60 | vector voq_input_map, 61 | vector voq_output_map, 62 | vector in_queue_info, 63 | vector out_queue_info, 64 | NetContext& net_ctx); 65 | 66 | void add_constrs(NetContext& net_ctx, map& constr_map); 67 | 68 | private: 69 | unsigned int leaf_id; 70 | unsigned int servers_per_leaf; 71 | unsigned int spine_cnt; 72 | }; 73 | 74 | class ReducedLeafXBarQM : public SwitchXBarQM { 75 | public: 76 | ReducedLeafXBarQM(cid_t id, 77 | unsigned int starting_qid, 78 | unsigned int servers_per_leaf, 79 | unsigned int spine_cnt, 80 | unsigned int total_time, 81 | vector voq_input_map, 82 | vector voq_output_map, 83 | vector in_queue_info, 84 | vector out_queue_info, 85 | NetContext& net_ctx); 86 | 87 | void add_constrs(NetContext& net_ctx, map& constr_map); 88 | 89 | private: 90 | unsigned int starting_qid; 91 | unsigned int servers_per_leaf; 92 | unsigned int spine_cnt; 93 | }; 94 | 95 | 96 | 97 | /* ********** SpineXBar ************ */ 98 | #endif /* switch_xbar_qm_hpp */ 99 | -------------------------------------------------------------------------------- /lib/qms/tbf_qm.hpp: -------------------------------------------------------------------------------- 1 | #include "queuing_module.hpp" 2 | 3 | struct TBFInfo { 4 | unsigned int max_tokens; 5 | unsigned int link_rate; 6 | unsigned int max_enq; 7 | }; 8 | 9 | class TBFQM : public QueuingModule { 10 | public: 11 | TBFQM(cid_t id, 12 | unsigned int total_time, 13 | QueueInfo in_queue_info, 14 | QueueInfo out_queue_info, 15 | NetContext& net_ctx, 16 | TBFInfo info); 17 | 18 | void add_constrs(NetContext& net_ctx, std::map& constr_map); 19 | std::vector token_queue; 20 | 21 | private: 22 | TBFInfo info; 23 | void add_proc_vars(NetContext& net_ctx); 24 | }; 25 | -------------------------------------------------------------------------------- /lib/query.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // query.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/20/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef query_hpp 10 | #define query_hpp 11 | 12 | #include "metric.hpp" 13 | #include "util.hpp" 14 | #include "workload.hpp" 15 | 16 | typedef vector qsum_t; 17 | typedef pair qdiff_t; 18 | typedef variant query_lhs_t; 19 | 20 | enum class query_quant_t { FORALL = 0, EXISTS }; 21 | 22 | class Query { 23 | public: 24 | Query(); 25 | Query(query_quant_t quant, 26 | time_range_t time_range, 27 | query_lhs_t query_lhs, 28 | metric_t metric, 29 | Op op, 30 | unsigned int thresh); 31 | 32 | query_quant_t get_quant(); 33 | time_range_t get_time_range(); 34 | metric_t get_metric(); 35 | query_lhs_t get_lhs(); 36 | Op get_op(); 37 | cid_t get_qid(); 38 | unsigned int get_thresh(); 39 | 40 | private: 41 | query_quant_t quant; 42 | time_range_t time_range; 43 | metric_t metric; 44 | query_lhs_t lhs; 45 | Op op; 46 | unsigned int thresh; 47 | }; 48 | 49 | #endif /* query_hpp */ 50 | -------------------------------------------------------------------------------- /lib/queue.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Queue.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/5/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef Queue_hpp 10 | #define Queue_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "metric.hpp" 17 | #include "net_context.hpp" 18 | #include "util.hpp" 19 | 20 | class Metric; 21 | enum class metric_t; 22 | 23 | enum class queue_t { QUEUE = 0, IMM_QUEUE, LINK }; 24 | 25 | struct QueueInfo { 26 | unsigned int size; 27 | unsigned int max_enq; 28 | unsigned int max_deq; 29 | unsigned int meta; 30 | queue_t type; 31 | }; 32 | 33 | /* *********************** Queue ********************** */ 34 | 35 | class Queue { 36 | public: 37 | Queue(cid_t module_id, 38 | cid_t queue_id, 39 | unsigned int size, 40 | unsigned int max_enq, 41 | unsigned int max_deq, 42 | unsigned int total_time, 43 | NetContext& net_ctx); 44 | 45 | unsigned int size(); 46 | unsigned int max_enq(); 47 | unsigned int max_deq(); 48 | 49 | vector& operator[](int ind); 50 | vector& elem(int ind); 51 | 52 | vector& enqs(unsigned int ind); 53 | expr& enq_cnt(unsigned int t); 54 | expr& deq_cnt(unsigned int t); 55 | 56 | void add_metric(metric_t metric_type, Metric* m); 57 | Metric* get_metric(metric_t metric_type); 58 | 59 | cid_t get_id() const; 60 | 61 | virtual void add_constrs(NetContext& net_ctx, map& constr_map); 62 | 63 | string get_model_str(model& m, NetContext& net_ctx, unsigned int t); 64 | 65 | friend ostream& operator<<(ostream& os, const Queue& q); 66 | 67 | protected: 68 | cid_t id; 69 | unsigned int size_; 70 | unsigned int max_enq_; 71 | unsigned int max_deq_; 72 | 73 | unsigned int total_time; 74 | 75 | vector* elems_; 76 | vector* enqs_; 77 | vector enq_cnt_; 78 | vector deq_cnt_; 79 | 80 | vector* tmp_val; 81 | vector* enq_ind; 82 | vector tail; 83 | vector tmp_tail; 84 | 85 | map metrics; 86 | 87 | void add_vars(NetContext& net_ctx); 88 | 89 | void sliding_window_vars(NetContext& net_ctx); 90 | virtual void sliding_window_constrs(NetContext& net_ctx, map& constr_map); 91 | }; 92 | 93 | /* *********************** ImmQueue ********************** */ 94 | /* Enqueued packets appear in the queue in the same time step */ 95 | 96 | class ImmQueue : public Queue { 97 | public: 98 | ImmQueue(cid_t module_id, 99 | cid_t queue_id, 100 | unsigned int size, 101 | unsigned int max_enq, 102 | unsigned int max_deq, 103 | unsigned int total_time, 104 | NetContext& net_ctx); 105 | 106 | friend ostream& operator<<(ostream& os, const ImmQueue& q); 107 | 108 | protected: 109 | void sliding_window_constrs(NetContext& net_ctx, map& constr_map); 110 | }; 111 | 112 | /* *********************** Link ********************** */ 113 | /* Packets that come in at time t, appear on the other side at time t + 1 */ 114 | 115 | class Link : public Queue { 116 | public: 117 | Link(cid_t module_id, cid_t queue_id, unsigned int total_time, NetContext& net_ctx); 118 | 119 | void add_constrs(NetContext& net_ctx, map& constr_map); 120 | 121 | 122 | friend ostream& operator<<(ostream& os, const Link& q); 123 | }; 124 | #endif /* Queue_hpp */ 125 | -------------------------------------------------------------------------------- /lib/queuing_module.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // queuing_module.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/9/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef queuing_module_hpp 10 | #define queuing_module_hpp 11 | 12 | #include 13 | #include 14 | 15 | #include "net_context.hpp" 16 | #include "queue.hpp" 17 | 18 | class QueuingModule { 19 | public: 20 | QueuingModule(cid_t id, 21 | unsigned int total_time, 22 | vector in_queue_info, 23 | vector out_queue_info, 24 | NetContext& net_ctx); 25 | 26 | virtual void add_constrs(NetContext& net_ctx, map& constr_map) = 0; 27 | 28 | unsigned long in_queue_cnt(); 29 | unsigned long out_queue_cnt(); 30 | 31 | Queue* get_in_queue(unsigned int ind); 32 | Queue* get_out_queue(unsigned int ind); 33 | void set_out_queue(unsigned int ind, Queue* queue); 34 | QueueInfo get_out_queue_info(unsigned int ind); 35 | 36 | cid_t get_id(); 37 | 38 | protected: 39 | cid_t id; 40 | unsigned int total_time; 41 | vector in_queues; 42 | vector out_queues; 43 | vector out_queue_info; 44 | 45 | void init(NetContext& net_ctx); 46 | 47 | private: 48 | virtual void add_proc_vars(NetContext& net_ctx) = 0; 49 | }; 50 | 51 | #endif /* queuing_module_hpp */ 52 | -------------------------------------------------------------------------------- /lib/search.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // search.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/20/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef search_hpp 10 | #define search_hpp 11 | 12 | #include 13 | #include 14 | 15 | #include "contention_point.hpp" 16 | #include "cost.hpp" 17 | #include "example.hpp" 18 | #include "input_only_solver.hpp" 19 | #include "params.hpp" 20 | #include "query.hpp" 21 | #include "shared_config.hpp" 22 | #include "spec_factory.hpp" 23 | #include "workload.hpp" 24 | 25 | class Search { 26 | public: 27 | Search(ContentionPoint* cp, 28 | Query query, 29 | unsigned int max_spec, 30 | SharedConfig* shared_config, 31 | string good_examples_fname, 32 | string bad_examples_fname); 33 | 34 | Search(ContentionPoint* cp, 35 | Query query, 36 | unsigned int max_spec, 37 | SharedConfig* shared_config, 38 | deque& good_ex, 39 | deque& bad_ex); 40 | 41 | void run(); 42 | 43 | unsigned int cost(Workload wl); 44 | 45 | private: 46 | ContentionPoint* cp; 47 | InputOnlySolver* input_only_solver; 48 | Query query; 49 | unsigned int max_spec; 50 | SharedConfig* shared_config = NULL; 51 | Dists* dists = NULL; 52 | qset_t target_queues; 53 | unsigned int in_queue_cnt; 54 | unsigned int total_time; 55 | 56 | SpecFactory spec_factory; 57 | Workload wl_last_step; 58 | bool last_input_infeasible; 59 | vector infeasible_wls; 60 | 61 | vector solutions; 62 | 63 | unsigned int close_count; 64 | 65 | deque bad_examples; 66 | deque good_examples; 67 | 68 | void init_wl(Workload& wl); 69 | bool check(Workload wl); 70 | void search(Workload wl); 71 | Workload refine(Workload wl); 72 | 73 | void pick_neighbors(Workload wl, vector& neighbors); 74 | Workload random_neighbor(Workload wl, unsigned int hops = 1); 75 | bool satisfies_bad_example(Workload wl); 76 | void populate_bad_examples(string fname); 77 | void populate_good_examples(string fname); 78 | unsigned int bad_example_match_count(Workload wl); 79 | unsigned int good_example_match_count(Workload wl); 80 | 81 | void print_stats(); 82 | 83 | /* ********** stats ********** */ 84 | unsigned int round_no = 0; 85 | unsigned long long int sum_check_time = 0; 86 | unsigned long long int max_check_time = 0; 87 | 88 | unsigned int rounds_in_local_search = 0; 89 | unsigned int reset_cnt = 0; 90 | unsigned int no_solver_call = 0; 91 | unsigned int input_only_solver_call = 0; 92 | unsigned int query_only_solver_call = 0; 93 | unsigned int full_solver_call = 0; 94 | unsigned int infeasible_input_cnt = 0; 95 | 96 | /* ********** stats ********** */ 97 | unsigned long long int sum_call_time = 0; 98 | unsigned int call_cnt = 0; 99 | }; 100 | 101 | #endif /* search_hpp */ 102 | -------------------------------------------------------------------------------- /lib/shared_config.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // shared_config.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/07/22. 6 | // Copyright © 2022 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef shared_config_hpp 10 | #define shared_config_hpp 11 | 12 | #include 13 | #include 14 | 15 | #include "metric.hpp" 16 | #include "params.hpp" 17 | #include "util.hpp" 18 | 19 | struct DistsParams { 20 | vector rhs_selection_weights = DEFAULT_RHS_SELECTION_WEIGHTS; 21 | 22 | unsigned int rhs_const_min = DEFAULT_RHS_CONST_MIN; 23 | unsigned int rhs_const_max = DEFAULT_RHS_CONST_MAX; 24 | 25 | unsigned int rhs_time_coeff_min = DEFAULT_RHS_TIME_COEFF_MIN; 26 | unsigned int rhs_time_coeff_max = DEFAULT_RHS_TIME_COEFF_MAX; 27 | 28 | vector trf_selection_weights = DEFAULT_TRF_SELECTION_WEIGHTS; 29 | vector wl_metric_selection_weights = DEFAULT_WL_METRIC_SELECTION_WEIGHTS; 30 | 31 | unsigned int in_queue_cnt = 0; 32 | unsigned int total_time = 0; 33 | 34 | unsigned int op_range_min = DEFAULT_COMP_RANGE_MIN; 35 | unsigned int op_range_max = DEFAULT_COMP_RANGE_MAX; 36 | 37 | unsigned int enq_range_min = DEFAULT_ENQ_RANGE_MIN; 38 | unsigned int enq_range_max = DEFAULT_ENQ_RANGE_MAX; 39 | 40 | unsigned int pkt_meta1_val_max = 0; 41 | unsigned int pkt_meta2_val_max = 0; 42 | 43 | unsigned int random_seed = DEFAULT_RANDOM_SEED; 44 | }; 45 | 46 | class Dists { 47 | public: 48 | Dists(DistsParams params); 49 | 50 | mt19937& get_gen(); 51 | double real_zero_to_one(); 52 | 53 | unsigned int rhs(); 54 | unsigned int rhs_const(); 55 | unsigned int rhs_time_coeff(); 56 | 57 | unsigned int trf(); 58 | 59 | metric_t wl_metric(); 60 | 61 | unsigned int input_queue(); 62 | unsigned int input_queue_cnt(); 63 | 64 | Op op(); 65 | 66 | unsigned int timestep(); 67 | unsigned int enq(); 68 | 69 | unsigned int pkt_metric1_val(); 70 | unsigned int pkt_metric2_val(); 71 | 72 | uniform_int_distribution& get_pkt_meta1_val_dist(); 73 | uniform_int_distribution& get_pkt_meta2_val_dist(); 74 | uniform_int_distribution& get_rhs_const_dist(); 75 | 76 | private: 77 | mt19937 gen; 78 | uniform_real_distribution real_zero_to_one_dist; 79 | 80 | discrete_distribution rhs_dist; 81 | uniform_int_distribution rhs_const_dist; 82 | uniform_int_distribution rhs_time_coeff_dist; 83 | discrete_distribution trf_dist; 84 | discrete_distribution wl_metric_dist; 85 | uniform_int_distribution input_queue_dist; 86 | uniform_int_distribution input_queue_cnt_dist; 87 | uniform_int_distribution op_dist; 88 | 89 | uniform_int_distribution timestep_dist; 90 | uniform_int_distribution enq_dist; 91 | 92 | uniform_int_distribution pkt_meta1_val_dist; 93 | uniform_int_distribution pkt_meta2_val_dist; 94 | }; 95 | 96 | class SharedConfig { 97 | public: 98 | SharedConfig(unsigned int total_time, 99 | unsigned int in_queue_cnt, 100 | qset_t target_queues, 101 | Dists* dists); 102 | 103 | unsigned int get_total_time(); 104 | unsigned int get_in_queue_cnt(); 105 | qset_t get_target_queues(); 106 | Dists* get_dists(); 107 | 108 | private: 109 | unsigned int total_time; 110 | unsigned int in_queue_cnt; 111 | qset_t target_queues; 112 | Dists* dists = NULL; 113 | }; 114 | 115 | #endif /* shared_config_hpp */ 116 | -------------------------------------------------------------------------------- /lib/solver.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // solver.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/10/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef solver_hpp 10 | #define solver_hpp 11 | 12 | #include "example.hpp" 13 | #include "workload.hpp" 14 | 15 | enum class solver_res_t { SAT = 0, UNSAT, UNKNOWN }; 16 | ostream& operator<<(ostream& os, const solver_res_t& res); 17 | 18 | class Solver { 19 | public: 20 | Solver() { 21 | } 22 | virtual solver_res_t check_workload_without_query(Workload wl) = 0; 23 | virtual solver_res_t check_workload_with_query(Workload wl, IndexedExample* eg) = 0; 24 | 25 | unsigned long long int get_check_workload_without_query_max_time(); 26 | unsigned long long int get_check_workload_without_query_avg_time(); 27 | 28 | unsigned long long int get_check_workload_with_query_max_time(); 29 | unsigned long long int get_check_workload_with_query_avg_time(); 30 | 31 | protected: 32 | unsigned long long int check_workload_without_query_max_time = 0; 33 | unsigned long long int check_workload_without_query_total_time = 0; 34 | unsigned int check_workload_without_query_total_invoc = 0; 35 | 36 | unsigned long long int check_workload_with_query_max_time = 0; 37 | unsigned long long int check_workload_with_query_total_time = 0; 38 | unsigned int check_workload_with_query_total_invoc = 0; 39 | }; 40 | 41 | #endif /* solver_hpp */ 42 | -------------------------------------------------------------------------------- /lib/spec_factory.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // spec_factory.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/14/22. 6 | // Copyright © 2022 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef spec_factory_hpp 10 | #define spec_factory_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "cost.hpp" 20 | #include "example.hpp" 21 | #include "metric.hpp" 22 | #include "shared_config.hpp" 23 | #include "util.hpp" 24 | #include "workload.hpp" 25 | 26 | struct RandomSpecGenerationParameters { 27 | bool time_valid; 28 | uniform_int_distribution const_dist; 29 | bool bound_with_dist = false; 30 | }; 31 | 32 | class SpecFactory { 33 | 34 | public: 35 | RandomSpecGenerationParameters get_metric_params(metric_t metric_type); 36 | 37 | SpecFactory(SharedConfig* shared_config); 38 | 39 | //**** TimedSpec ****// 40 | TimedSpec random_timed_spec(); 41 | void pick_neighbors(TimedSpec& spec, vector& neighbors); 42 | 43 | //**** WlSpec ****// 44 | WlSpec* random_wl_spec(); 45 | void pick_neighbors(WlSpec* spec, std::vector& neighbors); 46 | 47 | //**** COMP ****// 48 | WlSpec* random_comp(); 49 | void pick_neighbors(Comp& spec, vector& neighbors); 50 | 51 | //**** Rhs* ****// 52 | Expr* random_rhs(); 53 | Expr* random_rhs(RandomSpecGenerationParameters params); 54 | void pick_rhs_neighbors(Expr* rhs, vector& neighbors); 55 | void 56 | pick_rhs_neighbors(Expr* rhs, vector& neighbors, RandomSpecGenerationParameters params); 57 | 58 | //**** MExpr* ****// 59 | MExpr* random_m_expr(); 60 | void pick_m_expr_neighbors(MExpr* trf, vector& neighbors); 61 | 62 | //**** QSUM ****// 63 | qset_t random_qsum_qset(); 64 | QSum random_qsum(); 65 | void pick_neighbors(QSum& qsum, vector& neighbors); 66 | 67 | //**** INDIV ****// 68 | Indiv random_indiv(); 69 | void pick_neighbors(Indiv& indiv, vector& neighbors); 70 | 71 | //**** TIME ****// 72 | Time random_time(); 73 | 74 | //**** COMP ****/ 75 | Op random_op(); 76 | 77 | typedef WlSpec* (SpecFactory::*SpecGeneratorFuncPtr)(); 78 | vector spec_generators; 79 | 80 | private: 81 | void initializeSpecs(); 82 | 83 | unsigned int total_time; 84 | unsigned int in_queue_cnt; 85 | qset_t target_queues; 86 | Dists* dists = NULL; 87 | }; 88 | 89 | #endif /* spec_factory_hpp */ 90 | -------------------------------------------------------------------------------- /lib/tests.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // tests.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/05/22. 6 | // Copyright © 2022 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef tests_hpp 10 | #define tests_hpp 11 | 12 | #include 13 | 14 | using namespace std; 15 | 16 | typedef void e2e_test_func_t(string, string); 17 | 18 | void prio(string good_examples_file = "", string bad_examples_file = ""); 19 | 20 | void rr(string good_examples_file = "", string bad_examples_file = ""); 21 | 22 | void fq_codel(string good_examples_file = "", string bad_examples_file = ""); 23 | 24 | void loom(string good_examples_file = "", string bad_examples_file = ""); 25 | 26 | void leaf_spine_bw(string good_examples_file = "", string bad_examples_file = ""); 27 | 28 | void tbf(string good_examples_file = "", string bad_examples_file = ""); 29 | #endif /* tests_hpp */ 30 | -------------------------------------------------------------------------------- /lib/util.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // util.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/9/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef util_hpp 10 | #define util_hpp 11 | 12 | #pragma clang diagnostic push 13 | #pragma clang diagnostic ignored "-Wdocumentation" 14 | 15 | #include "z3++.h" 16 | 17 | #pragma clang diagnostic pop 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "params.hpp" 26 | 27 | using namespace z3; 28 | using namespace std::chrono; 29 | 30 | typedef pair qpair; 31 | typedef pair named_constr; 32 | 33 | //************************************* QSET *************************************// 34 | 35 | typedef set qset_t; 36 | 37 | bool is_superset(qset_t qset1, qset_t qset2); 38 | 39 | ostream& operator<<(ostream& os, const qset_t& qset); 40 | 41 | bool satisfies(unsigned int q, qset_t qset); 42 | 43 | //************************************* CID *************************************// 44 | typedef string cid_t; 45 | typedef pair cid_pair; 46 | 47 | cid_t get_unique_id(cid_t module_id, cid_t queue_id); 48 | 49 | //************************************* OP *************************************// 50 | class Op { 51 | public: 52 | enum class Type { GT = 0, GE, LT, LE, EQ }; 53 | 54 | Op(); 55 | Op(Op::Type op); 56 | 57 | Type get_type() const; 58 | 59 | friend ostream& operator<<(ostream& os, const Op& op); 60 | 61 | static bool eval(unsigned int lhs_val, const Op& op, unsigned int rhs_val); 62 | 63 | static Op random_op(); 64 | 65 | void neg(); 66 | 67 | bool operator==(const Op& other) const; 68 | bool operator<(const Op& other) const; 69 | 70 | private: 71 | Type type; 72 | }; 73 | 74 | //************************************* TIME RANGE *************************************// 75 | typedef pair time_range_t; 76 | bool is_superset(time_range_t t1, time_range_t t2); 77 | bool includes(time_range_t time_range, unsigned int t); 78 | ostream& operator<<(ostream& os, const time_range_t& time_range); 79 | 80 | //************************************* TIME *************************************// 81 | typedef time_point time_typ; 82 | time_typ noww(); 83 | unsigned long long int get_diff_sec(time_typ start, time_typ end); 84 | unsigned long long int get_diff_millisec(time_typ start, time_typ end); 85 | unsigned long long int get_diff_microsec(time_typ start, time_typ end); 86 | 87 | //************************************* OTHER *************************************// 88 | string banner(string b); 89 | 90 | template string format_string(const string& format, Args... args) { 91 | char vname[100]; 92 | snprintf(vname, 100, format.c_str(), args...); 93 | string s(vname); 94 | return s; 95 | } 96 | 97 | #ifdef DEBUG 98 | #define DEBUG_MSG(str) \ 99 | do { \ 100 | cout << str; \ 101 | } while (false) 102 | #else 103 | #define DEBUG_MSG(str) \ 104 | do { \ 105 | } while (false) 106 | #endif 107 | 108 | #endif /* util_hpp */ 109 | -------------------------------------------------------------------------------- /lib/workload.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // workload.hpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/19/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #ifndef workload_hpp 10 | #define workload_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "cost.hpp" 22 | #include "example.hpp" 23 | #include "metric.hpp" 24 | #include "util.hpp" 25 | 26 | /* -------------------------------------------------------------- 27 | The Grammar: 28 | Workload := /\ (TimedSpec) 29 | TimedSpec := forall t in [CONST, CONST] WlSpec 30 | WlSpec := SAME | INCR | DECR | COMP | UNIQ 31 | SAME := same[MTRC(Q, t)] 32 | INCR := incr[MTRC(Q, t)] 33 | DECR := decr[MTRC(Q, t)] 34 | UNIQ := uniq[MTRC(QSET, t)] 35 | COMP := LHS OP RHS 36 | LHS := MTRC_EXPR 37 | RHS := MTRC_EXPR | TIME | C 38 | MTRC_EXPR := QSUM | INDIV 39 | QSUM := SUM_[q in QSET] MTRC(q, t) 40 | INDIV := MTRC(Q, t) 41 | TIME := C.t 42 | ----------------------------------------------------------------- */ 43 | 44 | //************************************* RHS *************************************// 45 | class Expr { 46 | public: 47 | virtual ~Expr() = default; 48 | virtual unsigned int ast_size() const; 49 | virtual bool applies_to_queue(unsigned int queue) const; 50 | 51 | virtual bool operator==(const Expr& other) const; 52 | virtual bool operator<(const Expr& other) const; 53 | }; 54 | 55 | ostream& operator<<(ostream& os, const Expr* rhs); 56 | ostream& operator<<(ostream& os, const Expr& rhs); 57 | 58 | //************************************* LHS / MExpr *************************************// 59 | 60 | class MExpr : public Expr { 61 | public: 62 | virtual ~MExpr() = default; 63 | unsigned int ast_size() const override; 64 | bool applies_to_queue(unsigned int queue) const override; 65 | 66 | virtual bool operator==(const MExpr& other) const; 67 | virtual bool operator<(const MExpr& other) const; 68 | }; 69 | 70 | ostream& operator<<(ostream& os, const MExpr* m_expr); 71 | ostream& operator<<(ostream& os, const MExpr& m_expr); 72 | 73 | //************************************* TIME *************************************// 74 | 75 | class Time : public Expr { 76 | 77 | public: 78 | Time(unsigned int coeff); 79 | unsigned int get_coeff() const; 80 | 81 | private: 82 | unsigned int coeff; 83 | 84 | friend ostream& operator<<(ostream& os, const Time* time); 85 | friend ostream& operator<<(ostream& os, const Time& time); 86 | friend bool operator==(const Time& t1, const Time& t2); 87 | friend bool operator<(const Time& t1, const Time& t2); 88 | }; 89 | 90 | //************************************* Constant *************************************// 91 | 92 | class Constant : public Expr { 93 | 94 | public: 95 | Constant(unsigned int value); 96 | unsigned int get_value() const; 97 | 98 | private: 99 | unsigned int value; 100 | 101 | friend ostream& operator<<(ostream& os, const Constant* c); 102 | friend ostream& operator<<(ostream& os, const Constant& c); 103 | friend bool operator==(const Constant& c1, const Constant& c2); 104 | friend bool operator<(const Constant& c1, const Constant& c2); 105 | }; 106 | 107 | //************************************* QSUM *************************************// 108 | 109 | class QSum : public MExpr { 110 | 111 | public: 112 | QSum(qset_t qset, metric_t metric); 113 | 114 | unsigned int ast_size() const; 115 | bool applies_to_queue(unsigned int queue) const; 116 | 117 | qset_t get_qset() const; 118 | metric_t get_metric() const; 119 | 120 | private: 121 | qset_t qset; 122 | metric_t metric; 123 | 124 | friend ostream& operator<<(ostream& os, const QSum* tsum); 125 | friend ostream& operator<<(ostream& os, const QSum& tsum); 126 | friend bool operator==(const QSum& s1, const QSum& s2); 127 | friend bool operator<(const QSum& s1, const QSum& s2); 128 | friend class SpecFactory; 129 | }; 130 | 131 | //************************************* INDIV *************************************// 132 | 133 | class Indiv : public MExpr { 134 | 135 | public: 136 | Indiv(metric_t metric, unsigned int queue); 137 | 138 | bool applies_to_queue(unsigned int queue) const; 139 | 140 | unsigned int get_queue() const; 141 | metric_t get_metric() const; 142 | 143 | private: 144 | metric_t metric; 145 | unsigned int queue; 146 | 147 | friend ostream& operator<<(ostream& os, const Indiv* tone); 148 | friend ostream& operator<<(ostream& os, const Indiv& tone); 149 | friend bool operator==(const Indiv& s1, const Indiv& s2); 150 | friend bool operator<(const Indiv& s1, const Indiv& s2); 151 | }; 152 | 153 | //************************************* WlSpec *************************************// 154 | 155 | class WlSpec { 156 | public: 157 | virtual bool applies_to_queue(unsigned int queue) const = 0; 158 | 159 | virtual bool spec_is_empty() const; 160 | virtual bool spec_is_all() const; 161 | virtual unsigned int ast_size() const; 162 | 163 | friend ostream& operator<<(ostream& os, const WlSpec* wl_spec); 164 | virtual bool operator==(const WlSpec& other) const = 0; 165 | bool operator<(const WlSpec& other) const; 166 | virtual ~WlSpec() = default; 167 | 168 | protected: 169 | virtual string to_string() const = 0; 170 | 171 | private: 172 | virtual int type_id() const = 0; 173 | virtual bool less_than(const WlSpec& other) const = 0; 174 | }; 175 | 176 | //************************************* UNIQ *************************************// 177 | class Unique : public WlSpec { 178 | 179 | public: 180 | Unique(metric_t metric, qset_t qset); 181 | 182 | bool applies_to_queue(unsigned int queue) const override; 183 | 184 | qset_t get_qset() const; 185 | metric_t get_metric() const; 186 | 187 | // Override operators 188 | bool operator==(const WlSpec& other) const override; 189 | 190 | private: 191 | metric_t metric; 192 | qset_t qset; 193 | 194 | string to_string() const override; 195 | int type_id() const override; 196 | bool less_than(const WlSpec& other) const override; 197 | }; 198 | 199 | //************************************* SAME *************************************// 200 | class Same : public WlSpec { 201 | 202 | public: 203 | Same(metric_t metric, unsigned int queue); 204 | 205 | bool applies_to_queue(unsigned int queue) const override; 206 | 207 | unsigned int get_queue() const; 208 | metric_t get_metric() const; 209 | 210 | bool operator==(const WlSpec& other) const override; 211 | 212 | private: 213 | metric_t metric; 214 | unsigned int queue; 215 | 216 | string to_string() const override; 217 | int type_id() const override; 218 | bool less_than(const WlSpec& other) const override; 219 | }; 220 | 221 | //************************************* INCR *************************************// 222 | class Incr : public WlSpec { 223 | 224 | public: 225 | Incr(metric_t metric, unsigned int queue); 226 | 227 | bool applies_to_queue(unsigned int queue) const override; 228 | 229 | unsigned int get_queue() const; 230 | metric_t get_metric() const; 231 | 232 | bool operator==(const WlSpec& other) const override; 233 | 234 | private: 235 | metric_t metric; 236 | unsigned int queue; 237 | 238 | string to_string() const override; 239 | int type_id() const override; 240 | bool less_than(const WlSpec& other) const override; 241 | }; 242 | 243 | //************************************* DECR *************************************// 244 | class Decr : public WlSpec { 245 | 246 | public: 247 | Decr(metric_t metric, unsigned int queue); 248 | 249 | bool applies_to_queue(unsigned int queue) const override; 250 | 251 | unsigned int get_queue() const; 252 | metric_t get_metric() const; 253 | 254 | bool operator==(const WlSpec& other) const override; 255 | 256 | private: 257 | metric_t metric; 258 | unsigned int queue; 259 | 260 | string to_string() const override; 261 | int type_id() const override; 262 | bool less_than(const WlSpec& other) const override; 263 | }; 264 | 265 | //************************************* COMP *************************************// 266 | 267 | class Comp : public WlSpec { 268 | public: 269 | Comp(MExpr* lhs, Op op, Expr* rhs); 270 | 271 | virtual bool spec_is_empty() const override; 272 | bool spec_is_all() const override; 273 | unsigned int ast_size() const override; 274 | bool applies_to_queue(unsigned int queue) const override; 275 | pair get_zero_queues() const; 276 | 277 | 278 | MExpr* get_lhs() const; 279 | Op get_op() const; 280 | Expr* get_rhs() const; 281 | 282 | bool operator==(const WlSpec& other) const override; 283 | 284 | private: 285 | MExpr* lhs; 286 | Op op; 287 | Expr* rhs; 288 | 289 | bool is_empty = false; 290 | bool is_all = false; 291 | 292 | string to_string() const override; 293 | int type_id() const override; 294 | bool less_than(const WlSpec& other) const override; 295 | 296 | void normalize(); 297 | }; 298 | 299 | //************************************* Timed WlSpec *************************************// 300 | 301 | class TimedSpec { 302 | 303 | public: 304 | TimedSpec(WlSpec* wl_spec, time_range_t time_range, unsigned int total_time); 305 | TimedSpec(WlSpec* wl_spec, unsigned int until_time, unsigned int total_time); 306 | 307 | bool spec_is_empty() const; 308 | bool spec_is_all() const; 309 | bool applies_to_queue(unsigned int queue) const; 310 | 311 | time_range_t get_time_range() const; 312 | WlSpec* get_wl_spec() const; 313 | 314 | void set_time_range_ub(unsigned int ub); 315 | 316 | protected: 317 | WlSpec* wl_spec; 318 | time_range_t time_range; 319 | unsigned int total_time; 320 | 321 | bool is_empty = false; 322 | bool is_all = false; 323 | 324 | void normalize(); 325 | 326 | friend ostream& operator<<(ostream& os, const TimedSpec& spec); 327 | friend ostream& operator<<(ostream& os, const TimedSpec* spec); 328 | friend bool operator==(const TimedSpec& spec1, const TimedSpec& spec2); 329 | friend bool operator!=(const TimedSpec& spec1, const TimedSpec& spec2); 330 | friend bool operator<(const TimedSpec& spec1, const TimedSpec& spec2); 331 | }; 332 | 333 | //************************************* Workload *************************************// 334 | typedef map> timeline_t; 335 | 336 | class Workload { 337 | public: 338 | Workload(unsigned int max_size, unsigned int queue_cnt, unsigned int total_time); 339 | 340 | void clear(); 341 | void add_spec(TimedSpec spec); 342 | void rm_spec(TimedSpec spec); 343 | void mod_spec(TimedSpec old_spec, TimedSpec new_spec); 344 | 345 | unsigned long size() const; 346 | 347 | unsigned int get_max_size() const; 348 | unsigned int get_queue_cnt() const; 349 | unsigned int get_total_time() const; 350 | timeline_t get_timeline() const; 351 | set get_all_specs() const; 352 | 353 | bool is_empty() const; 354 | bool is_all() const; 355 | 356 | wl_cost_t cost() const; 357 | 358 | friend ostream& operator<<(ostream& os, const Workload& wl); 359 | friend ostream& operator<<(ostream& os, const Workload* wl); 360 | 361 | private: 362 | unsigned int max_size; 363 | unsigned int queue_cnt; 364 | unsigned int total_time; 365 | set empty_set; 366 | 367 | set all_specs; 368 | timeline_t timeline; 369 | 370 | bool empty = false; 371 | bool all = false; 372 | 373 | void normalize(); 374 | void normalize(time_range_t time_range); 375 | void regenerate_spec_set(); 376 | 377 | unsigned int ast_size() const; 378 | string get_timeline_str(); 379 | 380 | set add_time_range(time_range_t time_range); 381 | }; 382 | 383 | bool operator==(const Workload& wl1, const Workload& wl2); 384 | 385 | #endif /* workload_hpp */ 386 | -------------------------------------------------------------------------------- /scripts/perf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | TEST_NAME=$1 5 | FPERF_PATH="../build/fperf" 6 | 7 | function cleanup() { 8 | pkill -f fperf 9 | } 10 | 11 | function get_random() { 12 | RESULT=$RANDOM 13 | while awk '{print $2}' < rands.log | grep -q "$RESULT"; do 14 | RESULT=$RANDOM 15 | done 16 | echo $RESULT 17 | } 18 | 19 | function get_best_time() { 20 | tail -n 1 seeds.log | awk '{print $1}' 21 | # awk '{if ($1) print $1}' < "seeds.log" | sort -n | head -1 22 | } 23 | 24 | 25 | function main() { 26 | truncate -s 0 output.log 27 | 28 | for i in $(seq 1 6); do 29 | RAND="$(get_random)" 30 | echo "$RAND" >> rands.log 31 | $FPERF_PATH "$TEST_NAME" "$RAND" >> output.log & 32 | done 33 | 34 | ELAPSED_TIME=0 35 | 36 | while [ true ]; do 37 | echo "Elapsed Time: $ELAPSED_TIME" 38 | if [ -n "$(get_best_time)" ] && [ "$ELAPSED_TIME" -gt "$(get_best_time)" ]; then 39 | echo "Elapsed Time exceeded best time, skipping this round" 40 | break; 41 | fi 42 | if grep -q "FINISHED" "output.log"; then 43 | echo "Found finished process" 44 | BEST_SEED=$(awk '/FINISHED/{print $2}' < output.log | tail -n 1) 45 | echo "$ELAPSED_TIME $BEST_SEED" >> seeds.log 46 | break 47 | fi 48 | sleep 1 49 | ELAPSED_TIME=$(( $ELAPSED_TIME + 1)) 50 | done 51 | 52 | cleanup 53 | } 54 | 55 | main 56 | -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TEST_NAME=$1 4 | 5 | trap 'pkill -f fperf; exit;' SIGINT SIGTERM 6 | 7 | for i in $(seq 1 1000); do 8 | echo "Round: $i" 9 | ./perf.sh $TEST_NAME 10 | echo "----------------------" 11 | done 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/cost.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // cost.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/28/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "cost.hpp" 10 | #include "params.hpp" 11 | 12 | #include 13 | 14 | vector wl_cost_weights = {SPEC_CNT_WEIGHT, 15 | NUM_QUEUES_WITH_SPECS_WEIGHT, 16 | MAX_SPEC_CNT_PER_QUEUE_WEIGHT, 17 | AVG_SPEC_CNT_OVER_QUEUES, 18 | AVG_TIME_RANGE_OVER_SPECS_WEIGHT}; 19 | 20 | unsigned int uint_val(const wl_cost_t cost) { 21 | return cost; 22 | } 23 | 24 | unsigned int uint_val(const cost_t cost) { 25 | return EXAMPLE_WEIGHT_IN_COST * cost.first + uint_val(cost.second); 26 | } 27 | 28 | int operator-(const cost_t cost1, const cost_t cost2) { 29 | return ((int) uint_val(cost1)) - uint_val(cost2); 30 | } 31 | 32 | bool operator<(const cost_t cost1, const cost_t cost2) { 33 | return uint_val(cost1) < uint_val(cost2); 34 | } 35 | 36 | bool operator<=(const cost_t cost1, const cost_t cost2) { 37 | return uint_val(cost1) <= uint_val(cost2); 38 | } 39 | 40 | bool operator>(const cost_t cost1, const cost_t cost2) { 41 | return uint_val(cost1) > uint_val(cost2); 42 | } 43 | 44 | bool operator>=(const cost_t cost1, const cost_t cost2) { 45 | return uint_val(cost1) >= uint_val(cost2); 46 | } 47 | 48 | bool operator==(const cost_t cost1, const cost_t cost2) { 49 | return uint_val(cost1) == uint_val(cost2); 50 | } 51 | 52 | bool operator!=(const cost_t cost1, const cost_t cost2) { 53 | return uint_val(cost1) != uint_val(cost2); 54 | } 55 | -------------------------------------------------------------------------------- /src/cps/buggy_2l_rr_scheduler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // buggy_2l_rr_scheduler.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 08/03/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "buggy_2l_rr_scheduler.hpp" 10 | #include "buggy_2l_rr_qm.hpp" 11 | 12 | #include 13 | 14 | Buggy2LRRScheduler::Buggy2LRRScheduler(unsigned int queue_cnt, unsigned int total_time): 15 | ContentionPoint(total_time), 16 | queue_cnt(queue_cnt) { 17 | init(); 18 | } 19 | 20 | void Buggy2LRRScheduler::add_nodes() { 21 | // add a 2l_rr qm 22 | QueueInfo info; 23 | info.size = MAX_QUEUE_SIZE; 24 | info.max_enq = MAX_ENQ; 25 | info.max_deq = 1; 26 | 27 | cid_t m_id = "2LRR"; 28 | 29 | Buggy2LRRQM* rr_qm = new Buggy2LRRQM( 30 | m_id, total_time, vector(queue_cnt, info), info, net_ctx); 31 | 32 | nodes.push_back(m_id); 33 | id_to_qm[m_id] = rr_qm; 34 | } 35 | 36 | void Buggy2LRRScheduler::add_edges() { 37 | } 38 | 39 | void Buggy2LRRScheduler::add_metrics() { 40 | // CEnq 41 | for (unsigned int q = 0; q < in_queues.size(); q++) { 42 | Queue* queue = in_queues[q]; 43 | CEnq* ce = new CEnq(queue, total_time, net_ctx); 44 | cenq.push_back(ce); 45 | metrics[metric_t::CENQ][queue->get_id()] = ce; 46 | queue->add_metric(metric_t::CENQ, ce); 47 | } 48 | 49 | // CDeq 50 | for (unsigned int q = 0; q < in_queues.size(); q++) { 51 | Queue* queue = in_queues[q]; 52 | CDeq* cd = new CDeq(queue, total_time, net_ctx); 53 | cdeq.push_back(cd); 54 | metrics[metric_t::CDEQ][queue->get_id()] = cd; 55 | queue->add_metric(metric_t::CDEQ, cd); 56 | } 57 | 58 | // AIPG 59 | for (unsigned int q = 0; q < in_queues.size(); q++) { 60 | Queue* queue = in_queues[q]; 61 | AIPG* g = new AIPG(queue, total_time, net_ctx); 62 | aipg.push_back(g); 63 | metrics[metric_t::AIPG][queue->get_id()] = g; 64 | queue->add_metric(metric_t::AIPG, g); 65 | } 66 | } 67 | 68 | string Buggy2LRRScheduler::cp_model_str(model& m, NetContext& net_ctx, unsigned int t) { 69 | stringstream ss; 70 | 71 | cid_t rr_id = nodes[0]; 72 | Buggy2LRRQM* rr_qm = (Buggy2LRRQM*) id_to_qm[rr_id]; 73 | 74 | Queue* new_queues = rr_qm->new_fifo(); 75 | ss << new_queues->get_model_str(m, net_ctx, t) << endl; 76 | Queue* old_queues = rr_qm->old_fifo(); 77 | ss << old_queues->get_model_str(m, net_ctx, t) << endl; 78 | for (unsigned int q = 0; q < in_queues.size(); q++) { 79 | ss << (m.eval(rr_qm->inactive(q, t)).is_true() ? 1 : 0); 80 | } 81 | ss << endl; 82 | 83 | ss << "qid: cdeq" << endl; 84 | for (unsigned int q = 0; q < in_queues.size(); q++) { 85 | Queue* queue = in_queues[q]; 86 | ss << queue->get_id() << ": " << m.eval(cdeq[q]->val(t).second).get_numeral_int() << endl; 87 | } 88 | return ss.str(); 89 | } 90 | -------------------------------------------------------------------------------- /src/cps/loom_mqprio.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_mqprio.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "loom_mqprio.hpp" 10 | #include "loom_demux_qm.hpp" 11 | #include "loom_flow_enq_qm.hpp" 12 | #include "loom_nic_enq_qm.hpp" 13 | #include "priority_qm.hpp" 14 | #include "rr_qm.hpp" 15 | 16 | #include 17 | 18 | LoomMQPrio::LoomMQPrio(unsigned int nic_tx_queue_cnt, 19 | unsigned int per_core_flow_cnt, 20 | unsigned int total_time): 21 | ContentionPoint(total_time), 22 | nic_tx_queue_cnt(nic_tx_queue_cnt), 23 | per_core_flow_cnt(per_core_flow_cnt) { 24 | init(); 25 | } 26 | 27 | void LoomMQPrio::add_nodes() { 28 | QueueInfo info; 29 | info.size = MAX_QUEUE_SIZE; 30 | info.max_enq = MAX_ENQ; 31 | info.max_deq = info.size; 32 | info.type = queue_t::IMM_QUEUE; 33 | 34 | for (unsigned int i = 0; i < nic_tx_queue_cnt; i++) { 35 | 36 | // Create flow_enq_qm 37 | cid_t m_id = "FlowEnq" + to_string(i); 38 | LoomFlowEnqQM* flow_enq_qm = new LoomFlowEnqQM( 39 | m_id, total_time, vector(per_core_flow_cnt, info), info, info, net_ctx); 40 | 41 | nodes.push_back(m_id); 42 | id_to_qm[m_id] = flow_enq_qm; 43 | 44 | // Create the corresponding rr scheduler 45 | m_id = "RR" + to_string(i); 46 | RRQM* rr_qm = new RRQM( 47 | m_id, total_time, vector(tenant_cnt, info), info, net_ctx); 48 | 49 | nodes.push_back(m_id); 50 | id_to_qm[m_id] = rr_qm; 51 | } 52 | 53 | cid_t m_id = "NICEnq"; 54 | LoomNICEnqQM* nic_enq_qm = new LoomNICEnqQM( 55 | m_id, total_time, vector(nic_tx_queue_cnt, info), info, info, net_ctx); 56 | nodes.push_back(m_id); 57 | id_to_qm[m_id] = nic_enq_qm; 58 | 59 | m_id = "PRIO"; 60 | PriorityQM* prio_qm = new PriorityQM( 61 | m_id, total_time, vector(2, info), info, net_ctx); 62 | nodes.push_back(m_id); 63 | id_to_qm[m_id] = prio_qm; 64 | 65 | m_id = "EndDemux"; 66 | LoomDemuxQM* demux_qm = new LoomDemuxQM(m_id, total_time, info, info, info, net_ctx); 67 | nodes.push_back(m_id); 68 | id_to_qm[m_id] = demux_qm; 69 | } 70 | 71 | void LoomMQPrio::add_edges() { 72 | for (unsigned int i = 0; i < nic_tx_queue_cnt; i++) { 73 | cid_t flow_enq_id = "FlowEnq" + to_string(i); 74 | cid_t rr_id = "RR" + to_string(i); 75 | 76 | // modules edges 77 | vector edges; 78 | edges.push_back(rr_id); 79 | module_edges[flow_enq_id] = edges; 80 | 81 | // queue edges 82 | vector q_edges; 83 | for (unsigned int j = 0; j < tenant_cnt; j++) { 84 | q_edges.push_back(qpair(j, j)); 85 | } 86 | queue_edges[cid_pair(flow_enq_id, rr_id)] = q_edges; 87 | } 88 | 89 | cid_t nic_enq_id = "NICEnq"; 90 | vector rr_nic_edges; 91 | rr_nic_edges.push_back(nic_enq_id); 92 | 93 | for (unsigned int i = 0; i < nic_tx_queue_cnt; i++) { 94 | cid_t rr_id = "RR" + to_string(i); 95 | 96 | // modules edges 97 | module_edges[rr_id] = rr_nic_edges; 98 | 99 | // queue edges 100 | vector q_edges; 101 | q_edges.push_back(qpair(0, i)); 102 | queue_edges[cid_pair(rr_id, nic_enq_id)] = q_edges; 103 | } 104 | 105 | cid_t prio_id = "PRIO"; 106 | 107 | // module edges 108 | vector nic_prio_edges; 109 | nic_prio_edges.push_back(prio_id); 110 | module_edges[nic_enq_id] = nic_prio_edges; 111 | 112 | // queue edges 113 | vector nic_prio_qedges; 114 | nic_prio_qedges.push_back(qpair(0, 0)); 115 | nic_prio_qedges.push_back(qpair(1, 1)); 116 | queue_edges[cid_pair(nic_enq_id, prio_id)] = nic_prio_qedges; 117 | 118 | cid_t demux_id = "EndDemux"; 119 | 120 | // module edges 121 | vector prio_demux_edges; 122 | prio_demux_edges.push_back(demux_id); 123 | module_edges[prio_id] = prio_demux_edges; 124 | 125 | // queue edges 126 | vector prio_demux_qedges; 127 | prio_demux_qedges.push_back(qpair(0, 0)); 128 | queue_edges[cid_pair(prio_id, demux_id)] = prio_demux_qedges; 129 | } 130 | 131 | void LoomMQPrio::add_metrics() { 132 | // CEnq 133 | for (unsigned int q = 0; q < in_queues.size(); q++) { 134 | Queue* queue = in_queues[q]; 135 | CEnq* ce = new CEnq(queue, total_time, net_ctx); 136 | cenq.push_back(ce); 137 | metrics[metric_t::CENQ][queue->get_id()] = ce; 138 | queue->add_metric(metric_t::CENQ, ce); 139 | } 140 | 141 | for (unsigned int q = 0; q < out_queues.size(); q++) { 142 | Queue* queue = out_queues[q]; 143 | CEnq* ce = new CEnq(queue, total_time, net_ctx); 144 | cenq.push_back(ce); 145 | metrics[metric_t::CENQ][queue->get_id()] = ce; 146 | queue->add_metric(metric_t::CENQ, ce); 147 | } 148 | 149 | // AIPG 150 | for (unsigned int q = 0; q < in_queues.size(); q++) { 151 | Queue* queue = in_queues[q]; 152 | AIPG* g = new AIPG(queue, total_time, net_ctx); 153 | aipg.push_back(g); 154 | metrics[metric_t::AIPG][queue->get_id()] = g; 155 | queue->add_metric(metric_t::AIPG, g); 156 | } 157 | } 158 | 159 | string LoomMQPrio::cp_model_str(model& m, NetContext& net_ctx, unsigned int t) { 160 | // TODO: implement 161 | (void) net_ctx; 162 | 163 | stringstream ss; 164 | for (unsigned int q = 0; q < out_queues.size(); q++) { 165 | Queue* queue = out_queues[q]; 166 | ss << queue->get_id() << ": " 167 | << m.eval(queue->get_metric(metric_t::CENQ)->val(t).second).get_numeral_int() << endl; 168 | } 169 | return ss.str(); 170 | } 171 | -------------------------------------------------------------------------------- /src/cps/priority_scheduler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // priority_scheduler.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/16/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "priority_scheduler.hpp" 10 | #include "priority_qm.hpp" 11 | 12 | #include 13 | 14 | PrioScheduler::PrioScheduler(unsigned int prio_levels, unsigned int total_time): 15 | ContentionPoint(total_time), 16 | prio_levels(prio_levels) { 17 | init(); 18 | } 19 | 20 | void PrioScheduler::add_nodes() { 21 | // add a priority qm 22 | QueueInfo info; 23 | info.size = 10; 24 | info.max_enq = 4; 25 | info.max_deq = 1; 26 | info.type = queue_t::QUEUE; 27 | 28 | cid_t m_id = "Prio"; 29 | 30 | PriorityQM* prio_qm = new PriorityQM( 31 | m_id, total_time, vector(prio_levels, info), info, net_ctx); 32 | 33 | nodes.push_back(m_id); 34 | 35 | id_to_qm[m_id] = prio_qm; 36 | } 37 | 38 | void PrioScheduler::add_edges() { 39 | } 40 | 41 | void PrioScheduler::add_metrics() { 42 | 43 | // CBlocked 44 | for (unsigned int q = 0; q < in_queues.size(); q++) { 45 | Queue* queue = in_queues[q]; 46 | CBlocked* cb = new CBlocked(queue, total_time, net_ctx); 47 | cblocked.push_back(cb); 48 | metrics[metric_t::CBLOCKED][queue->get_id()] = cb; 49 | queue->add_metric(metric_t::CBLOCKED, cb); 50 | } 51 | 52 | 53 | // CEnq 54 | for (unsigned int q = 0; q < in_queues.size(); q++) { 55 | Queue* queue = in_queues[q]; 56 | CEnq* ce = new CEnq(queue, total_time, net_ctx); 57 | cenq.push_back(ce); 58 | metrics[metric_t::CENQ][queue->get_id()] = ce; 59 | queue->add_metric(metric_t::CENQ, ce); 60 | } 61 | 62 | 63 | // AIPG 64 | for (unsigned int q = 0; q < in_queues.size(); q++) { 65 | Queue* queue = in_queues[q]; 66 | AIPG* g = new AIPG(queue, total_time, net_ctx); 67 | aipg.push_back(g); 68 | metrics[metric_t::AIPG][queue->get_id()] = g; 69 | queue->add_metric(metric_t::AIPG, g); 70 | } 71 | } 72 | 73 | string PrioScheduler::cp_model_str(model& m, NetContext& net_ctx, unsigned int t) { 74 | (void) net_ctx; 75 | stringstream ss; 76 | for (unsigned int q = 0; q < in_queues.size(); q++) { 77 | Queue* queue = in_queues[q]; 78 | ss << queue->get_id() << ": " << m.eval(cblocked[q]->val(t).second).get_numeral_int() 79 | << ", " << m.eval(cenq[q]->val(t).second).get_numeral_int() << endl; 80 | } 81 | return ss.str(); 82 | } 83 | -------------------------------------------------------------------------------- /src/cps/rr_scheduler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // rr_scheduler.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/18/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "rr_scheduler.hpp" 10 | #include "rr_qm.hpp" 11 | 12 | #include 13 | 14 | RRScheduler::RRScheduler(unsigned int queue_cnt, unsigned int total_time): 15 | ContentionPoint(total_time), 16 | queue_cnt(queue_cnt) { 17 | init(); 18 | } 19 | 20 | void RRScheduler::add_nodes() { 21 | // add a rr qm 22 | QueueInfo info; 23 | info.size = MAX_QUEUE_SIZE; 24 | info.max_enq = MAX_ENQ; 25 | info.max_deq = 1; 26 | 27 | cid_t m_id = "RR"; 28 | 29 | RRQM* rr_qm = new RRQM(m_id, total_time, vector(queue_cnt, info), info, net_ctx); 30 | 31 | nodes.push_back(m_id); 32 | id_to_qm[m_id] = rr_qm; 33 | } 34 | 35 | void RRScheduler::add_edges() { 36 | } 37 | 38 | void RRScheduler::add_metrics() { 39 | // CEnq 40 | for (unsigned int q = 0; q < in_queues.size(); q++) { 41 | Queue* queue = in_queues[q]; 42 | CEnq* ce = new CEnq(queue, total_time, net_ctx); 43 | cenq.push_back(ce); 44 | metrics[metric_t::CENQ][queue->get_id()] = ce; 45 | queue->add_metric(metric_t::CENQ, ce); 46 | } 47 | 48 | // CDeq 49 | for (unsigned int q = 0; q < in_queues.size(); q++) { 50 | Queue* queue = in_queues[q]; 51 | CDeq* cd = new CDeq(queue, total_time, net_ctx); 52 | cdeq.push_back(cd); 53 | metrics[metric_t::CDEQ][queue->get_id()] = cd; 54 | queue->add_metric(metric_t::CDEQ, cd); 55 | } 56 | 57 | /* 58 | // QSize 59 | for (unsigned int q = 0; q < in_queues.size(); q++){ 60 | Queue* queue = in_queues[q]; 61 | QSize* qs = new QSize(queue, total_time, net_ctx); 62 | qsize.push_back(qs); 63 | metrics[metric_t::QSIZE][queue->get_id()] = qs; 64 | queue->add_metric(metric_t::QSIZE, qs); 65 | } 66 | */ 67 | 68 | // AIPG 69 | for (unsigned int q = 0; q < in_queues.size(); q++) { 70 | Queue* queue = in_queues[q]; 71 | AIPG* g = new AIPG(queue, total_time, net_ctx); 72 | aipg.push_back(g); 73 | metrics[metric_t::AIPG][queue->get_id()] = g; 74 | queue->add_metric(metric_t::AIPG, g); 75 | } 76 | } 77 | 78 | string RRScheduler::cp_model_str(model& m, NetContext& net_ctx, unsigned int t) { 79 | (void) net_ctx; 80 | 81 | stringstream ss; 82 | cid_t rr_id = nodes[0]; 83 | RRQM* rr_qm = (RRQM*) id_to_qm[rr_id]; 84 | 85 | int last_served_queue = -1; 86 | for (unsigned int q = 0; q < in_queues.size(); q++) { 87 | if (m.eval(rr_qm->last_served_queue(q, t)).is_true()) { 88 | last_served_queue = q; 89 | break; 90 | } 91 | } 92 | ss << "last serviced queue: " << last_served_queue << endl; 93 | ss << "qid: cenq, cdeq, deq_cnt" << endl; 94 | for (unsigned int q = 0; q < in_queues.size(); q++) { 95 | Queue* queue = in_queues[q]; 96 | ss << queue->get_id() << ": " << m.eval(cenq[q]->val(t).second).get_numeral_int() << ", " 97 | << m.eval(cdeq[q]->val(t).second).get_numeral_int() << ", " << 98 | // m.eval(qsize[q]->val(t)).get_numeral_int() << ", " << 99 | m.eval(queue->deq_cnt(t)).get_numeral_int() << endl; 100 | } 101 | return ss.str(); 102 | } 103 | -------------------------------------------------------------------------------- /src/cps/tbf.cpp: -------------------------------------------------------------------------------- 1 | #include "tbf.hpp" 2 | #include 3 | 4 | 5 | TBF::TBF(unsigned int total_time, TBFInfo info): ContentionPoint(total_time), info(info) { 6 | init(); 7 | } 8 | 9 | Queue* TBF::get_in_queue() { 10 | return get_in_queues()[0]; 11 | } 12 | 13 | Queue* TBF::get_out_queue() { 14 | return out_queues[0]; 15 | } 16 | 17 | void TBF::add_nodes() { 18 | // add a rr qm 19 | QueueInfo in_queue_info; 20 | in_queue_info.size = MAX_QUEUE_SIZE; 21 | in_queue_info.max_enq = info.max_enq; 22 | in_queue_info.max_deq = MAX_QUEUE_SIZE; 23 | in_queue_info.type = queue_t::QUEUE; 24 | 25 | QueueInfo out_queue_info; 26 | out_queue_info.size = MAX_QUEUE_SIZE; 27 | out_queue_info.max_enq = MAX_QUEUE_SIZE; 28 | out_queue_info.max_deq = MAX_QUEUE_SIZE; 29 | out_queue_info.type = queue_t::QUEUE; 30 | 31 | cid_t m_id = "TBF"; 32 | 33 | TBFQM* tbf_qm = new TBFQM(m_id, total_time, in_queue_info, out_queue_info, net_ctx, info); 34 | 35 | nodes.push_back(m_id); 36 | id_to_qm[m_id] = tbf_qm; 37 | qm = tbf_qm; 38 | } 39 | 40 | void TBF::add_edges() { 41 | } 42 | 43 | void TBF::add_metrics() { 44 | // CEnq 45 | CEnq* ce = new CEnq(get_in_queue(), total_time, net_ctx); 46 | cenq.push_back(ce); 47 | metrics[metric_t::CENQ][get_in_queue()->get_id()] = ce; 48 | get_in_queue()->add_metric(metric_t::CENQ, ce); 49 | 50 | // CDeq 51 | CDeq* cd = new CDeq(get_in_queue(), total_time, net_ctx); 52 | cdeq.push_back(cd); 53 | metrics[metric_t::CDEQ][get_in_queue()->get_id()] = cd; 54 | get_in_queue()->add_metric(metric_t::CDEQ, cd); 55 | 56 | // Deq 57 | Deq* d = new Deq(get_in_queue(), total_time, net_ctx); 58 | deq.push_back(d); 59 | metrics[metric_t::DEQ][get_in_queue()->get_id()] = d; 60 | get_in_queue()->add_metric(metric_t::DEQ, d); 61 | } 62 | 63 | std::string TBF::cp_model_str(model& m, NetContext& net_ctx, unsigned int t) { 64 | (void) net_ctx; 65 | stringstream ss; 66 | ss << "Token Queue: " << m.eval(qm->token_queue[t]) << endl; 67 | return ss.str(); 68 | } -------------------------------------------------------------------------------- /src/example.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // example.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/15/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "example.hpp" 10 | 11 | #include 12 | 13 | ostream& operator<<(ostream& os, const Example& eg) { 14 | os << "total time: " << eg.total_time << endl; 15 | os << eg.query_qid << endl; 16 | 17 | os << "enqs:" << endl; 18 | for (map>::const_iterator it = eg.enqs.begin(); it != eg.enqs.end(); 19 | it++) { 20 | os << it->first << " "; 21 | for (unsigned int t = 0; t < it->second.size(); t++) { 22 | os << it->second[t] << " "; 23 | } 24 | os << endl; 25 | } 26 | 27 | os << "deqs:" << endl; 28 | for (map>::const_iterator it = eg.deqs.begin(); it != eg.deqs.end(); 29 | it++) { 30 | os << it->first << " "; 31 | for (unsigned int t = 0; t < it->second.size(); t++) { 32 | os << it->second[t] << " "; 33 | } 34 | os << endl; 35 | } 36 | 37 | os << "pkts metadata: " << endl; 38 | for (map>>::const_iterator it = eg.enqs_meta1.begin(); 39 | it != eg.enqs_meta1.end(); 40 | it++) { 41 | cid_t qid = it->first; 42 | os << qid << " "; 43 | for (unsigned int t = 0; t < it->second.size(); t++) { 44 | vector meta1 = it->second[t]; 45 | vector meta2 = eg.enqs_meta2.at(qid)[t]; 46 | for (unsigned int p = 0; p < meta1.size(); p++) { 47 | os << "[" << meta1[p] << ", " << meta2[p] << "] "; 48 | } 49 | os << " | "; 50 | } 51 | os << endl; 52 | } 53 | return os; 54 | } 55 | 56 | 57 | void write_examples_to_file(deque& examples, string fname) { 58 | ofstream out; 59 | out.open(fname); 60 | 61 | for (unsigned int i = 0; i < examples.size(); i++) { 62 | Example* eg = examples[i]; 63 | 64 | out << eg->query_qid << " "; 65 | out << eg->total_time << " "; 66 | out << eg->enqs.size() << endl; 67 | 68 | for (map>::iterator it = eg->enqs.begin(); it != eg->enqs.end(); 69 | it++) { 70 | out << it->first << " "; 71 | for (unsigned int t = 0; t < it->second.size(); t++) { 72 | out << it->second[t] << " "; 73 | } 74 | out << endl; 75 | } 76 | 77 | for (map>>::iterator it = eg->enqs_meta1.begin(); 78 | it != eg->enqs_meta1.end(); 79 | it++) { 80 | out << it->first << " "; 81 | for (unsigned int t = 0; t < it->second.size(); t++) { 82 | vector meta = it->second[t]; 83 | for (unsigned int p = 0; p < meta.size(); p++) { 84 | out << meta[p] << " "; 85 | } 86 | out << "| "; 87 | } 88 | out << endl; 89 | } 90 | 91 | for (map>>::iterator it = eg->enqs_meta2.begin(); 92 | it != eg->enqs_meta2.end(); 93 | it++) { 94 | out << it->first << " "; 95 | for (unsigned int t = 0; t < it->second.size(); t++) { 96 | vector meta = it->second[t]; 97 | for (unsigned int p = 0; p < meta.size(); p++) { 98 | out << meta[p] << " "; 99 | } 100 | out << "| "; 101 | } 102 | out << endl; 103 | } 104 | 105 | for (map>::iterator it = eg->deqs.begin(); it != eg->deqs.end(); 106 | it++) { 107 | out << it->first << " "; 108 | for (unsigned int t = 0; t < it->second.size(); t++) { 109 | out << it->second[t] << " "; 110 | } 111 | out << endl; 112 | } 113 | } 114 | out.close(); 115 | } 116 | 117 | vector u_split_line(string line) { 118 | vector parts; 119 | 120 | size_t next_part = line.find(" ", 0); 121 | while (next_part != string::npos) { 122 | string part = line.substr(0, next_part); 123 | if (part.size() > 0) parts.push_back((unsigned int) stoi(part)); 124 | line = line.substr(next_part + 1); 125 | next_part = line.find(" ", 0); 126 | } 127 | if (line.size() > 0) parts.push_back((unsigned int) stoi(line)); 128 | return parts; 129 | } 130 | 131 | vector s_split_line(string line) { 132 | vector parts; 133 | 134 | size_t next_part = line.find(" ", 0); 135 | while (next_part != string::npos) { 136 | string part = line.substr(0, next_part); 137 | if (part.size() > 0) parts.push_back(stoi(part)); 138 | line = line.substr(next_part + 1); 139 | next_part = line.find(" ", 0); 140 | } 141 | if (line.size() > 0) parts.push_back(stoi(line)); 142 | return parts; 143 | } 144 | 145 | 146 | /* 147 | File format: 148 | query_qid total_time num_queues 149 | num_queue lines for enqs: 150 | qid enq1 enq2 ... 151 | num_queue lines for enqs_meta1: 152 | qid meta00 meta01 meta02 ... | meta10 meta11 ... 153 | num_queue lines in the format above for enqs_meta2 154 | num_queue lines for deqs: 155 | qid deq1 deq2 ... 156 | */ 157 | void read_examples_from_file(deque& examples, string fname) { 158 | ifstream in; 159 | in.open(fname); 160 | 161 | if (!in.is_open()) { 162 | cout << "Cannot open file: " << fname << endl; 163 | return; 164 | } 165 | string line; 166 | while (getline(in, line)) { 167 | Example* eg = new Example(); 168 | 169 | size_t next_part = line.find(" ", 0); 170 | eg->query_qid = line.substr(0, next_part); 171 | line = line.substr(next_part + 1); 172 | 173 | vector u_parts = u_split_line(line); 174 | if (u_parts.size() != 2) { 175 | cout << "Bad input file format" << endl; 176 | in.close(); 177 | return; 178 | } 179 | 180 | eg->total_time = u_parts[0]; 181 | unsigned int num_queues = u_parts[1]; 182 | 183 | for (unsigned int i = 0; i < num_queues; i++) { 184 | getline(in, line); 185 | 186 | size_t next_part = line.find(" ", 0); 187 | cid_t qid = line.substr(0, next_part); 188 | line = line.substr(next_part + 1); 189 | 190 | u_parts = u_split_line(line); 191 | 192 | if (u_parts.size() != eg->total_time) { 193 | cout << "Bad input file format" << endl; 194 | in.close(); 195 | return; 196 | } 197 | 198 | eg->enqs[qid] = u_parts; 199 | } 200 | 201 | for (unsigned int i = 0; i < num_queues; i++) { 202 | getline(in, line); 203 | size_t next_part = line.find(" ", 0); 204 | cid_t qid = line.substr(0, next_part); 205 | line = line.substr(next_part + 1); 206 | 207 | vector> enqs_meta1; 208 | for (unsigned int t = 0; t < eg->total_time; t++) { 209 | size_t next_part = line.find("|", 0); 210 | 211 | if (next_part == string::npos) { 212 | cout << "Bad input file format" << endl; 213 | in.close(); 214 | return; 215 | } 216 | 217 | string enqs_meta_str = line.substr(0, next_part); 218 | line = line.substr(next_part + 1); 219 | 220 | vector s_parts = s_split_line(enqs_meta_str); 221 | enqs_meta1.push_back(s_parts); 222 | } 223 | 224 | eg->enqs_meta1[qid] = enqs_meta1; 225 | } 226 | 227 | for (unsigned int i = 0; i < num_queues; i++) { 228 | getline(in, line); 229 | size_t next_part = line.find(" ", 0); 230 | cid_t qid = line.substr(0, next_part); 231 | line = line.substr(next_part + 1); 232 | 233 | vector> enqs_meta2; 234 | for (unsigned int t = 0; t < eg->total_time; t++) { 235 | size_t next_part = line.find("|", 0); 236 | 237 | if (next_part == string::npos) { 238 | cout << "Bad input file format" << endl; 239 | in.close(); 240 | return; 241 | } 242 | 243 | string enqs_meta_str = line.substr(0, next_part); 244 | line = line.substr(next_part + 1); 245 | 246 | vector s_parts = s_split_line(enqs_meta_str); 247 | enqs_meta2.push_back(s_parts); 248 | } 249 | 250 | eg->enqs_meta2[qid] = enqs_meta2; 251 | } 252 | 253 | for (unsigned int i = 0; i < num_queues; i++) { 254 | getline(in, line); 255 | 256 | size_t next_part = line.find(" ", 0); 257 | cid_t qid = line.substr(0, next_part); 258 | line = line.substr(next_part + 1); 259 | 260 | u_parts = u_split_line(line); 261 | 262 | if (u_parts.size() != eg->total_time) { 263 | cout << "Bad input file format" << endl; 264 | in.close(); 265 | return; 266 | } 267 | 268 | eg->deqs[qid] = u_parts; 269 | } 270 | 271 | examples.push_back(eg); 272 | } 273 | } 274 | 275 | ostream& operator<<(ostream& os, const IndexedExample& eg) { 276 | os << "total time: " << eg.total_time << endl; 277 | os << eg.query_qid << endl; 278 | 279 | os << "enqs:" << endl; 280 | for (unsigned int i = 0; i < eg.enqs.size(); i++) { 281 | os << i << " "; 282 | for (unsigned int t = 0; t < eg.enqs[i].size(); t++) { 283 | os << eg.enqs[i][t] << " "; 284 | } 285 | os << endl; 286 | } 287 | 288 | os << "deqs:" << endl; 289 | for (unsigned int i = 0; i < eg.deqs.size(); i++) { 290 | os << i << " "; 291 | for (unsigned int t = 0; t < eg.deqs[i].size(); t++) { 292 | os << eg.deqs[i][t] << " "; 293 | } 294 | os << endl; 295 | } 296 | 297 | os << "pkts metadata: " << endl; 298 | for (unsigned int i = 0; i < eg.enqs_meta1.size(); i++) { 299 | os << i << " "; 300 | for (unsigned int t = 0; t < eg.enqs_meta1[i].size(); t++) { 301 | vector meta1 = eg.enqs_meta1[i][t]; 302 | vector meta2 = eg.enqs_meta2[i][t]; 303 | for (unsigned int p = 0; p < meta1.size(); p++) { 304 | os << "[" << meta1[p] << ", " << meta2[p] << "] "; 305 | } 306 | os << " | "; 307 | } 308 | os << endl; 309 | } 310 | return os; 311 | } 312 | 313 | ostream& operator<<(ostream& os, const Trace& tr) { 314 | os << "total time: " << tr.total_time << endl; 315 | 316 | os << "enqs:" << endl; 317 | for (unsigned int i = 0; i < tr.enqs.size(); i++) { 318 | os << i << " "; 319 | for (unsigned int t = 0; t < tr.enqs[i].size(); t++) { 320 | os << tr.enqs[i][t] << " "; 321 | } 322 | os << endl; 323 | } 324 | return os; 325 | } 326 | -------------------------------------------------------------------------------- /src/input_only_solver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // input_only_solver.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/10/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "input_only_solver.hpp" 10 | 11 | solver_res_t InputOnlySolver::check_workload_without_query(Workload wl) { 12 | (void) wl; 13 | time_typ start_time = noww(); 14 | 15 | 16 | // TODO: implement 17 | 18 | 19 | //------------ Timing Stats 20 | time_typ end_time = noww(); 21 | unsigned long long int seconds = get_diff_sec(start_time, end_time); 22 | 23 | check_workload_without_query_total_invoc++; 24 | check_workload_without_query_total_time += seconds; 25 | if (seconds > check_workload_without_query_max_time) { 26 | check_workload_without_query_max_time = seconds; 27 | } 28 | //------------------------- 29 | 30 | return solver_res_t::UNKNOWN; 31 | } 32 | 33 | solver_res_t InputOnlySolver::check_workload_with_query(Workload wl, IndexedExample* eg) { 34 | (void) wl; 35 | (void) eg; 36 | 37 | time_typ start_time = noww(); 38 | 39 | 40 | // TODO: implement 41 | 42 | 43 | //------------ Timing Stats 44 | time_typ end_time = noww(); 45 | unsigned long long int seconds = get_diff_sec(start_time, end_time); 46 | 47 | check_workload_with_query_total_invoc++; 48 | check_workload_with_query_total_time += seconds; 49 | if (seconds > check_workload_with_query_max_time) { 50 | check_workload_with_query_max_time = seconds; 51 | } 52 | //------------------------- 53 | 54 | return solver_res_t::UNKNOWN; 55 | } 56 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 3/2/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "tests.hpp" 14 | #include "util.hpp" 15 | 16 | #ifdef DEBUG 17 | bool debug = true; 18 | #else 19 | bool debug = false; 20 | #endif 21 | 22 | using namespace std; 23 | 24 | map e2e_tests = {{"prio", prio}, 25 | {"rr", rr}, 26 | {"fq_codel", fq_codel}, 27 | {"loom", loom}, 28 | {"leaf_spine_bw", leaf_spine_bw}, 29 | {"tbf", tbf}}; 30 | 31 | const string help_message = "Usage: ./fperf TEST_NAME"; 32 | 33 | int main(int argc, const char* argv[]) { 34 | vector arguments(argv + 1, argv + argc); 35 | 36 | if (arguments.size() != 1) throw invalid_argument("Invalid number of arguments"); 37 | 38 | if (arguments[0] == "--help") { 39 | cout << help_message << endl; 40 | return 0; 41 | } 42 | 43 | string test_name = arguments[0]; 44 | if (e2e_tests.find(test_name) == e2e_tests.end()) 45 | throw invalid_argument("Unknown test: " + test_name); 46 | 47 | e2e_tests.find(test_name)->second("", ""); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/metric.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // metric.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/17/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | 10 | #include "metric.hpp" 11 | 12 | #include 13 | #include 14 | 15 | const map Metric::properties = {{metric_t::CENQ, {true, true, true}}, 16 | {metric_t::AIPG, {true, false, false}}, 17 | {metric_t::DST, {true, false, false}}, 18 | {metric_t::ECMP, {true, false, false}}, 19 | {metric_t::QSIZE, 20 | {true, false, false}}, 21 | {metric_t::CDEQ, {true, true, true}}, 22 | {metric_t::CBLOCKED, 23 | {true, false, false}}}; 24 | 25 | Metric::Metric(metric_t m, Queue* queue, unsigned int total_time, NetContext& net_ctx): 26 | m_type(m), 27 | queue(queue), 28 | total_time(total_time) { 29 | stringstream ss; 30 | ss << m; 31 | 32 | id = get_unique_id(queue->get_id(), ss.str()); 33 | 34 | for (unsigned int t = 0; t < total_time; t++) { 35 | value_.push_back(net_ctx.bool_val(false)); 36 | valid_.push_back(net_ctx.bool_val(false)); 37 | } 38 | } 39 | 40 | m_val_expr_t Metric::val(unsigned int ind) { 41 | return m_val_expr_t(valid_[ind], value_[ind]); 42 | } 43 | 44 | void Metric::init(NetContext& net_ctx) { 45 | populate_val_exprs(net_ctx); 46 | } 47 | 48 | cid_t Metric::get_id() { 49 | return id; 50 | } 51 | 52 | metric_t Metric::get_type() { 53 | return m_type; 54 | } 55 | 56 | ostream& operator<<(ostream& os, const metric_t& metric) { 57 | switch (metric) { 58 | case (metric_t::CENQ): os << "cenq"; break; 59 | case (metric_t::QSIZE): os << "qsize"; break; 60 | case (metric_t::CDEQ): os << "cdeq"; break; 61 | case (metric_t::DEQ): os << "deq"; break; 62 | case (metric_t::CBLOCKED): os << "cblocked"; break; 63 | case (metric_t::AIPG): os << "aipg"; break; 64 | case (metric_t::DST): os << "dst"; break; 65 | case (metric_t::ECMP): os << "ecmp"; break; 66 | } 67 | return os; 68 | } 69 | -------------------------------------------------------------------------------- /src/metrics/aipg.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // aipg.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 8/5/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "aipg.hpp" 10 | 11 | AIPG::AIPG(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::AIPG, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void AIPG::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | 18 | res.valid = true; 19 | if (time == 0) { 20 | res.value = 0; 21 | return; 22 | } 23 | if (eg->enqs[qind][time] == 0) { 24 | eval(eg, time - 1, qind, res); 25 | return; 26 | } 27 | if (eg->enqs[qind][time] > 1) { 28 | res.value = 0; 29 | return; 30 | } 31 | 32 | int last_enq_time = -1; 33 | for (int t = time - 1; t >= 0; t--) { 34 | if (eg->enqs[qind][t] > 0) { 35 | last_enq_time = t; 36 | break; 37 | } 38 | } 39 | 40 | if (last_enq_time >= 0) { 41 | res.value = time - last_enq_time; 42 | return; 43 | } else { 44 | for (int t = time + 1; t < (int) eg->total_time; t++) { 45 | if (eg->enqs[qind][t] > 0) { 46 | last_enq_time = t; 47 | break; 48 | } 49 | } 50 | } 51 | 52 | if (last_enq_time >= 0) 53 | res.value = last_enq_time - time; 54 | else 55 | res.value = eg->total_time; 56 | } 57 | 58 | void AIPG::populate_val_exprs(NetContext& net_ctx) { 59 | // value 60 | value_[0] = net_ctx.int_val(0); 61 | 62 | for (unsigned int t1 = 1; t1 < total_time; t1++) { 63 | 64 | // When everything before and after is zero 65 | // TODO: total_time or total_time - t1? 66 | expr val_expr = net_ctx.int_val(total_time); 67 | 68 | for (unsigned int t2 = total_time - 1; t2 > t1; t2--) { 69 | val_expr = ite(queue->enq_cnt(t2) > 0, net_ctx.int_val(t2 - t1), val_expr); 70 | } 71 | 72 | for (unsigned int t2 = 0; t2 < t1; t2++) { 73 | val_expr = ite(queue->enq_cnt(t2) > 0, net_ctx.int_val(t1 - t2), val_expr); 74 | } 75 | 76 | value_[t1] = ite(queue->enq_cnt(t1) > 1, 77 | net_ctx.int_val(0), 78 | ite(queue->enq_cnt(t1) <= 0, value_[t1 - 1], val_expr)); 79 | 80 | // valid 81 | for (unsigned int t = 0; t < total_time; t++) { 82 | valid_[t] = net_ctx.bool_val(true); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/metrics/cblocked.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // cblocked.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/17/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "cblocked.hpp" 10 | 11 | CBlocked::CBlocked(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::CBLOCKED, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void CBlocked::eval(const IndexedExample* eg, 17 | unsigned int time, 18 | unsigned int qind, 19 | metric_val& res) { 20 | res.valid = true; 21 | unsigned int enq_sum = 0; 22 | unsigned int deq_sum = 0; 23 | unsigned int cblocked = 0; 24 | for (unsigned int t = 0; t <= time; t++) { 25 | // Only if deq is always less than the length 26 | // of the queue at that moment 27 | unsigned int len = enq_sum - deq_sum; 28 | if (len > 0 && eg->deqs[qind][t] == 0) { 29 | cblocked++; 30 | } else { 31 | cblocked = 0; 32 | } 33 | enq_sum += eg->enqs[qind][t]; 34 | deq_sum += eg->deqs[qind][t]; 35 | } 36 | res.value = cblocked; 37 | } 38 | 39 | void CBlocked::populate_val_exprs(NetContext& net_ctx) { 40 | // Value 41 | expr blocked = net_ctx.pkt2val(queue->elem(0)[0]) && queue->deq_cnt(0) == 0; 42 | value_[0] = ite(blocked, net_ctx.int_val(1), net_ctx.int_val(0)); 43 | 44 | for (unsigned int t = 1; t < total_time; t++) { 45 | blocked = net_ctx.pkt2val(queue->elem(0)[t]) && queue->deq_cnt(t) == 0; 46 | value_[t] = ite(blocked, value_[t - 1] + 1, net_ctx.int_val(0)); 47 | } 48 | 49 | // Valid 50 | for (unsigned int t = 0; t < total_time; t++) { 51 | valid_[t] = net_ctx.bool_val(true); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/metrics/cdeq.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // cdeq.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/19/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "cdeq.hpp" 10 | 11 | CDeq::CDeq(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::CDEQ, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void CDeq::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | 18 | res.valid = true; 19 | res.value = 0; 20 | for (unsigned int t = 0; t <= time; t++) { 21 | res.value += eg->deqs[qind][t]; 22 | } 23 | } 24 | 25 | void CDeq::populate_val_exprs(NetContext& net_ctx) { 26 | // value 27 | value_[0] = queue->deq_cnt(0); 28 | 29 | for (unsigned int t = 1; t < total_time; t++) { 30 | value_[t] = value_[t - 1] + queue->deq_cnt(t); 31 | } 32 | 33 | // valid 34 | for (unsigned int t = 0; t < total_time; t++) { 35 | valid_[t] = net_ctx.bool_val(true); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/metrics/cenq.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // cenq.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/11/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "cenq.hpp" 10 | 11 | CEnq::CEnq(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::CENQ, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void CEnq::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | res.valid = true; 18 | res.value = 0; 19 | for (unsigned int t = 0; t <= time; t++) { 20 | res.value += eg->enqs[qind][t]; 21 | } 22 | } 23 | 24 | void CEnq::populate_val_exprs(NetContext& net_ctx) { 25 | // value 26 | value_[0] = queue->enq_cnt(0); 27 | for (unsigned int t = 1; t < total_time; t++) { 28 | value_[t] = value_[t - 1] + queue->enq_cnt(t); 29 | } 30 | 31 | // valid 32 | for (unsigned int t = 0; t < total_time; t++) { 33 | valid_[t] = net_ctx.bool_val(true); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/metrics/deq.cpp: -------------------------------------------------------------------------------- 1 | #include "deq.hpp" 2 | 3 | Deq::Deq(Queue* queue, unsigned int total_time, NetContext& net_ctx): 4 | Metric(metric_t::DEQ, queue, total_time, net_ctx) { 5 | init(net_ctx); 6 | } 7 | 8 | void Deq::populate_val_exprs(NetContext& net_ctx) { 9 | 10 | for (unsigned int t = 0; t < total_time; t++) { 11 | valid_[t] = net_ctx.bool_val(true); 12 | value_[t] = queue->deq_cnt(t); 13 | } 14 | } 15 | 16 | void Deq::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | res.valid = true; 18 | res.value = eg->deqs[qind][time]; 19 | } 20 | -------------------------------------------------------------------------------- /src/metrics/dst.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // dst.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 06/06/23. 6 | // Copyright © 2023 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "dst.hpp" 10 | 11 | Dst::Dst(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::CENQ, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void Dst::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | 18 | vector enqs_meta1 = eg->enqs_meta1[qind][time]; 19 | if (enqs_meta1.size() == 0) { 20 | res.valid = false; 21 | return; 22 | } 23 | 24 | res.value = enqs_meta1[0]; 25 | for (unsigned int i = 1; i < enqs_meta1.size(); i++) { 26 | // FIXME: change enqs_meta2 to unsigned int 27 | if (enqs_meta1[i] != static_cast(res.value)) { 28 | res.valid = false; 29 | return; 30 | } 31 | } 32 | 33 | res.valid = true; 34 | } 35 | 36 | void Dst::populate_val_exprs(NetContext& net_ctx) { 37 | 38 | for (unsigned int t = 0; t < total_time; t++) { 39 | value_[t] = net_ctx.pkt2meta1(queue->enqs(0)[t]); 40 | } 41 | 42 | for (unsigned int t = 0; t < total_time; t++) { 43 | expr base_meta1 = net_ctx.pkt2meta1(queue->enqs(0)[t]); 44 | valid_[t] = net_ctx.pkt2val(queue->enqs(0)[t]); 45 | for (unsigned int e = 1; e < queue->max_enq(); e++) { 46 | expr pkt = queue->enqs(e)[t]; 47 | expr val = net_ctx.pkt2val(pkt); 48 | expr meta1 = net_ctx.pkt2meta1(pkt); 49 | valid_[t] = valid_[t] && (!val || (meta1 == base_meta1)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/metrics/ecmp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ecmp.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 06/06/23. 6 | // Copyright © 2023 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "ecmp.hpp" 10 | 11 | Ecmp::Ecmp(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::CENQ, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | void Ecmp::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 17 | 18 | vector enqs_meta2 = eg->enqs_meta2[qind][time]; 19 | if (enqs_meta2.size() == 0) { 20 | res.valid = false; 21 | return; 22 | } 23 | 24 | res.value = enqs_meta2[0]; 25 | for (unsigned int i = 1; i < enqs_meta2.size(); i++) { 26 | // FIXME: change enqs_meta2 to unsigned int 27 | if (enqs_meta2[i] != static_cast(res.value)) { 28 | res.valid = false; 29 | return; 30 | } 31 | } 32 | 33 | res.valid = true; 34 | } 35 | 36 | void Ecmp::populate_val_exprs(NetContext& net_ctx) { 37 | 38 | for (unsigned int t = 0; t < total_time; t++) { 39 | value_[t] = net_ctx.pkt2meta2(queue->enqs(0)[t]); 40 | } 41 | 42 | // Define valid_[t] 43 | for (unsigned int t = 0; t < total_time; t++) { 44 | expr base_meta2 = net_ctx.pkt2meta2(queue->enqs(0)[t]); 45 | valid_[t] = net_ctx.pkt2val(queue->enqs(0)[t]); 46 | for (unsigned int e = 1; e < queue->max_enq(); e++) { 47 | expr pkt = queue->enqs(e)[t]; 48 | expr val = net_ctx.pkt2val(pkt); 49 | expr meta2 = net_ctx.pkt2meta2(pkt); 50 | valid_[t] = valid_[t] && (!val || (meta2 == base_meta2)); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/metrics/qsize.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // qsize.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/19/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "qsize.hpp" 10 | 11 | QSize::QSize(Queue* queue, unsigned int total_time, NetContext& net_ctx): 12 | Metric(metric_t::QSIZE, queue, total_time, net_ctx) { 13 | init(net_ctx); 14 | } 15 | 16 | // TODO: FIX for leaf_spine_lat 17 | void QSize::eval(const IndexedExample* eg, unsigned int time, unsigned int qind, metric_val& res) { 18 | res.valid = true; 19 | unsigned int enq_sum = 0; 20 | unsigned int deq_sum = 0; 21 | for (unsigned int t = 0; t < time; t++) { 22 | enq_sum += eg->enqs[qind][t]; 23 | deq_sum += eg->deqs[qind][t]; 24 | } 25 | // Only if deq is always less than the length 26 | // of the queue at any point in time 27 | res.value = enq_sum - deq_sum; 28 | } 29 | 30 | void QSize::populate_val_exprs(NetContext& net_ctx) { 31 | 32 | // Value 33 | for (unsigned int t = 0; t < total_time; t++) { 34 | expr size_expr = net_ctx.int_val(0); 35 | for (unsigned int e = 0; e <= queue->size() - 1; e++) { 36 | expr pkt = queue->elem(e)[t]; 37 | expr val = net_ctx.pkt2val(pkt); 38 | size_expr = ite(val, net_ctx.int_val(e + 1), size_expr); 39 | } 40 | 41 | value_[t] = size_expr; 42 | } 43 | 44 | // Valid 45 | for (unsigned int t = 0; t < total_time; t++) { 46 | valid_[t] = net_ctx.bool_val(true); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/net_context.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // NetContext.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 4/2/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "net_context.hpp" 10 | #include 11 | 12 | NetContext::NetContext() { 13 | } 14 | 15 | expr NetContext::pkt_const(char const* name) { 16 | char val_vname[100]; 17 | strcpy(val_vname, name); 18 | strcat(val_vname, "_val"); 19 | expr val_var = ctx.bool_const(val_vname); 20 | 21 | char meta1_vname[100]; 22 | strcpy(meta1_vname, name); 23 | strcat(meta1_vname, "_meta1"); 24 | expr meta1_var = ctx.int_const(meta1_vname); 25 | 26 | char meta2_vname[100]; 27 | strcpy(meta2_vname, name); 28 | strcat(meta2_vname, "_meta2"); 29 | expr meta2_var = ctx.int_const(meta2_vname); 30 | 31 | bool_var_cnt += 1; 32 | int_var_cnt += 2; 33 | return (ptup) (val_var, meta1_var, meta2_var); 34 | } 35 | 36 | expr NetContext::pkt2val(expr pkt) { 37 | return (*ptup_projs)[VAL_IND](pkt); 38 | } 39 | 40 | expr NetContext::pkt2meta1(expr pkt) { 41 | return (*ptup_projs)[META1_IND](pkt); 42 | } 43 | 44 | expr NetContext::pkt2meta2(expr pkt) { 45 | return (*ptup_projs)[META2_IND](pkt); 46 | } 47 | 48 | expr NetContext::pkt_val(bool val, int meta1, int meta2) { 49 | expr vval = ctx.bool_val(val); 50 | expr vmeta1 = ctx.int_val(meta1); 51 | expr vmeta2 = ctx.int_val(meta2); 52 | return (ptup) (vval, vmeta1, vmeta2); 53 | } 54 | 55 | expr NetContext::null_pkt() { 56 | expr null_val = ctx.bool_val(false); 57 | expr null_meta1 = ctx.int_val(0); 58 | expr null_meta2 = ctx.int_val(0); 59 | return (ptup) (null_val, null_meta1, null_meta2); 60 | } 61 | 62 | expr NetContext::int_const(char* name) { 63 | int_var_cnt++; 64 | return ctx.int_const(name); 65 | } 66 | 67 | expr NetContext::int_val(int n) { 68 | return ctx.int_val(n); 69 | } 70 | 71 | expr NetContext::bool_const(char* name) { 72 | bool_var_cnt++; 73 | return ctx.bool_const(name); 74 | } 75 | 76 | expr NetContext::bool_val(bool b) { 77 | return ctx.bool_val(b); 78 | } 79 | 80 | context& NetContext::z3_ctx() { 81 | return ctx; 82 | } 83 | 84 | unsigned long NetContext::get_bool_var_cnt() { 85 | return bool_var_cnt; 86 | } 87 | 88 | unsigned long NetContext::get_int_var_cnt() { 89 | return int_var_cnt; 90 | } 91 | -------------------------------------------------------------------------------- /src/qms/loom_demux_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_demux_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/4/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "loom_demux_qm.hpp" 10 | 11 | LoomDemuxQM::LoomDemuxQM(cid_t id, 12 | unsigned int total_time, 13 | QueueInfo in_queue_info, 14 | QueueInfo out_queue_info1, 15 | QueueInfo out_queue_info2, 16 | NetContext& net_ctx): 17 | QueuingModule(id, 18 | total_time, 19 | vector{in_queue_info}, 20 | vector{out_queue_info1, out_queue_info2}, 21 | net_ctx) { 22 | init(net_ctx); 23 | } 24 | 25 | 26 | void LoomDemuxQM::add_proc_vars(NetContext& net_ctx) { 27 | (void) net_ctx; 28 | } 29 | 30 | void LoomDemuxQM::add_constrs(NetContext& net_ctx, map& constr_map) { 31 | char constr_name[100]; 32 | 33 | const unsigned int tenant1_spark = 1; 34 | const unsigned int tenant2_spark = 2; 35 | const unsigned int tenant2_memcached = 3; 36 | 37 | Queue* input_queue = in_queues[0]; 38 | 39 | for (unsigned int t = 0; t < total_time; t++) { 40 | expr head_pkt = input_queue->elem(0)[t]; 41 | expr not_empty = net_ctx.pkt2val(head_pkt); 42 | 43 | // If not empty, deq one from the input queue 44 | snprintf(constr_name, 100, "%s_input_deq_cnt_%d", id.c_str(), t); 45 | expr constr_expr = implies(not_empty, input_queue->deq_cnt(t) == 1); 46 | constr_map.insert(named_constr(constr_name, constr_expr)); 47 | 48 | // Decide which output queue to put the packet in 49 | expr pkt_class = net_ctx.pkt2meta1(head_pkt); 50 | snprintf(constr_name, 100, "%s_tenant1_pkt_%d", id.c_str(), t); 51 | constr_expr = implies(not_empty && pkt_class == (int) tenant1_spark, 52 | out_queues[0]->enqs(0)[t] == head_pkt); 53 | constr_map.insert(named_constr(constr_name, constr_expr)); 54 | 55 | snprintf(constr_name, 100, "%s_not_tenant1_pkt_%d", id.c_str(), t); 56 | constr_expr = implies(not_empty && pkt_class != (int) tenant1_spark, 57 | out_queues[0]->enqs(0)[t] == net_ctx.null_pkt()); 58 | constr_map.insert(named_constr(constr_name, constr_expr)); 59 | 60 | snprintf(constr_name, 100, "%s_tenant2_pkt_%d", id.c_str(), t); 61 | constr_expr = implies(not_empty && (pkt_class == (int) tenant2_spark || 62 | pkt_class == (int) tenant2_memcached), 63 | out_queues[1]->enqs(0)[t] == head_pkt); 64 | constr_map.insert(named_constr(constr_name, constr_expr)); 65 | 66 | snprintf(constr_name, 100, "%s_not_tenant2_pkt_%d", id.c_str(), t); 67 | constr_expr = implies(not_empty && (pkt_class != (int) tenant2_spark && 68 | pkt_class != (int) tenant2_memcached), 69 | out_queues[1]->enqs(0)[t] == net_ctx.null_pkt()); 70 | constr_map.insert(named_constr(constr_name, constr_expr)); 71 | 72 | // Take care of the case where the input queue is empty 73 | snprintf(constr_name, 100, "%s_empty_input_no_deq_%d", id.c_str(), t); 74 | constr_expr = implies(!not_empty, input_queue->deq_cnt(t) == 0); 75 | constr_map.insert(named_constr(constr_name, constr_expr)); 76 | 77 | for (unsigned int q = 0; q < out_queues.size(); q++) { 78 | snprintf(constr_name, 100, "%s_empty_input_no_enq_%d_%d", id.c_str(), q, t); 79 | expr constr_expr = implies(!not_empty, out_queues[q]->enqs(0)[t] == net_ctx.null_pkt()); 80 | constr_map.insert(named_constr(constr_name, constr_expr)); 81 | } 82 | 83 | 84 | // Make sure nothing else gets pushed to the output queue 85 | for (unsigned int q = 0; q < out_queues.size(); q++) { 86 | Queue* outq = out_queues[q]; 87 | for (unsigned int i = 1; i < outq->max_enq(); i++) { 88 | snprintf(constr_name, 100, "%s_only_one_output_%d_%d_%d", id.c_str(), q, i, t); 89 | expr constr_expr = outq->enqs(i)[t] == net_ctx.null_pkt(); 90 | constr_map.insert(named_constr(constr_name, constr_expr)); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/qms/loom_flow_enq_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_flow_enq_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "loom_flow_enq_qm.hpp" 10 | #include 11 | 12 | LoomFlowEnqQM::LoomFlowEnqQM(cid_t id, 13 | unsigned int total_time, 14 | vector in_queue_info, 15 | QueueInfo out_queue_info1, 16 | QueueInfo out_queue_info2, 17 | NetContext& net_ctx): 18 | QueuingModule( 19 | id, total_time, in_queue_info, vector{out_queue_info1, out_queue_info2}, net_ctx) { 20 | // Ensure the outqueue for tenant 2's max enq is even even number 21 | if (out_queue_info2.max_enq % 2 != 0) { 22 | throw "LoomFlowEnqQM invalid configuartion"; 23 | } 24 | 25 | init(net_ctx); 26 | } 27 | 28 | 29 | void LoomFlowEnqQM::add_proc_vars(NetContext& net_ctx) { 30 | (void) net_ctx; 31 | } 32 | 33 | void LoomFlowEnqQM::constrs_if_not_taken(NetContext& net_ctx, map& constr_map) { 34 | char constr_name[100]; 35 | 36 | const unsigned int tenant1_spark = 1; 37 | const unsigned int tenant2_spark = 2; 38 | const unsigned int tenant2_memcached = 3; 39 | 40 | // Tenant 1 41 | 42 | Queue* tenant1_inq = in_queues[0]; 43 | Queue* tenant1_outq = out_queues[0]; 44 | for (unsigned int t = 0; t < total_time; t++) { 45 | for (unsigned int i = 0; i < tenant1_outq->max_enq(); i++) { 46 | expr in_pkt = tenant1_inq->elem(i)[t]; 47 | // set enqs of the output queue equal to the first max_enq packets of input queue 48 | snprintf(constr_name, 100, "%s_tenant1_out_enqs[%d][%d]", id.c_str(), i, t); 49 | expr constr_expr = tenant1_outq->enqs(i)[t] == in_pkt; 50 | constr_map.insert(named_constr(constr_name, constr_expr)); 51 | 52 | // set deq_cnt of input queue based on validity of enqs of output queue most max_enq 53 | snprintf(constr_name, 100, "%s_tenant1_in_deq_cnt[%d]_is_%d", id.c_str(), t, i); 54 | constr_expr = implies(net_ctx.pkt2val(in_pkt), tenant1_inq->deq_cnt(t) > (int) i); 55 | constr_map.insert(named_constr(constr_name, constr_expr)); 56 | } 57 | } 58 | 59 | // Tenant 2 60 | // 1. Make sure if there are max_enq packets in both queues, they get enqueued. 61 | // we can do NICEnq style, but the order of visiting src packets one from 62 | // queue 2 and one from queue 3, until max_enq in both queues. 63 | // 2. Track whether each src packet made it, set the deq_cnt accordingly. 64 | 65 | Queue* tenant2_outq = out_queues[1]; 66 | 67 | for (unsigned int t = 0; t < total_time; t++) { 68 | vector le_i_gets_j(2 * tenant2_outq->max_enq(), net_ctx.bool_val(false)); 69 | for (unsigned int i = 0; i < tenant2_outq->max_enq(); i++) { 70 | 71 | expr prev_elems_invalid = net_ctx.bool_val(true); 72 | for (unsigned int j = i; j < 2 * tenant2_outq->max_enq(); j++) { 73 | unsigned int qid = 1 + (j % 2); 74 | unsigned int offset = j / 2; 75 | 76 | expr in_pkt = in_queues[qid]->elem(offset)[t]; 77 | expr cond = (prev_elems_invalid && net_ctx.pkt2val(in_pkt)); 78 | 79 | snprintf(constr_name, 80 | 100, 81 | "%s_tenant2_out_enqs[%d][%d]_is_inq[%d][%d]", 82 | id.c_str(), 83 | i, 84 | t, 85 | qid, 86 | offset); 87 | expr constr_expr = implies(cond && !le_i_gets_j[j], 88 | tenant2_outq->enqs(i)[t] == in_pkt); 89 | constr_map.insert(named_constr(constr_name, constr_expr)); 90 | 91 | string app_name = "spark"; 92 | if (qid == 2) app_name = "memcached"; 93 | 94 | snprintf(constr_name, 95 | 100, 96 | "%s_tenant2_%s_deq_cnt[%d]_is_gt_%d_because_%d", 97 | id.c_str(), 98 | app_name.c_str(), 99 | t, 100 | offset, 101 | i); 102 | constr_expr = implies(cond && !le_i_gets_j[j], 103 | in_queues[qid]->deq_cnt(t) > (int) offset); 104 | constr_map.insert(named_constr(constr_name, constr_expr)); 105 | 106 | prev_elems_invalid = prev_elems_invalid && 107 | (!net_ctx.pkt2val(in_pkt) || le_i_gets_j[j]); 108 | le_i_gets_j[j] = le_i_gets_j[j] || cond; 109 | } 110 | 111 | snprintf(constr_name, 100, "%s_tenant2_out_enqs[%d][%d]_is_null", id.c_str(), i, t); 112 | expr constr_expr = implies(prev_elems_invalid, 113 | tenant2_outq->enqs(i)[t] == net_ctx.null_pkt()); 114 | constr_map.insert(named_constr(constr_name, constr_expr)); 115 | } 116 | } 117 | 118 | // make sure all pkts in all queues have valid metadata 119 | for (unsigned int t = 0; t < total_time; t++) { 120 | for (unsigned int q = 0; q < in_queues.size(); q++) { 121 | 122 | int queue_class = tenant1_spark; 123 | if (q == 1) queue_class = tenant2_spark; 124 | if (q == 2) queue_class = tenant2_memcached; 125 | 126 | for (unsigned int i = 0; i < in_queues[q]->max_enq(); i++) { 127 | snprintf( 128 | constr_name, 100, "%s_only_valid_meta_in_enq[%d][%d][%d]", id.c_str(), q, i, t); 129 | expr pkt = in_queues[q]->enqs(i)[t]; 130 | expr pkt_class = net_ctx.pkt2meta1(pkt); 131 | expr constr_expr = implies(net_ctx.pkt2val(pkt), pkt_class == queue_class); 132 | constr_map.insert(named_constr(constr_name, constr_expr)); 133 | } 134 | } 135 | } 136 | } 137 | void LoomFlowEnqQM::add_constrs(NetContext& net_ctx, map& constr_map) { 138 | constrs_if_not_taken(net_ctx, constr_map); 139 | } 140 | -------------------------------------------------------------------------------- /src/qms/loom_nic_enq_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // loom_nic_enq_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 5/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "loom_nic_enq_qm.hpp" 10 | #include 11 | 12 | LoomNICEnqQM::LoomNICEnqQM(cid_t id, 13 | unsigned int total_time, 14 | vector in_queue_info, 15 | QueueInfo out_queue_info1, 16 | QueueInfo out_queue_info2, 17 | NetContext& net_ctx): 18 | QueuingModule( 19 | id, total_time, in_queue_info, vector{out_queue_info1, out_queue_info2}, net_ctx) { 20 | 21 | unsigned min_max_out_enq = out_queue_info1.max_enq; 22 | if (out_queue_info2.max_enq < min_max_out_enq) { 23 | min_max_out_enq = out_queue_info2.max_enq; 24 | } 25 | 26 | if (in_queue_info.size() % min_max_out_enq != 0) { 27 | throw "LoomNICEnqQM invalid configuartion"; 28 | } 29 | // TODO: shouldn't this be reversed? 30 | per_queue_share = (unsigned int) in_queue_info.size() / min_max_out_enq; 31 | init(net_ctx); 32 | } 33 | 34 | 35 | void LoomNICEnqQM::add_proc_vars(NetContext& net_ctx) { 36 | (void) net_ctx; 37 | } 38 | 39 | void LoomNICEnqQM::constrs_if_not_taken(NetContext& net_ctx, map& constr_map) { 40 | char constr_name[100]; 41 | 42 | const unsigned int tenant1_spark = 1; 43 | const unsigned int tenant2_spark = 2; 44 | const unsigned int tenant2_memcached = 3; 45 | 46 | 47 | for (unsigned int t = 0; t < total_time; t++) { 48 | for (unsigned int q = 0; q < in_queues.size(); q++) { 49 | for (unsigned int i = 0; i < per_queue_share; i++) { 50 | Queue* inq = in_queues[q]; 51 | 52 | expr in_pkt = inq->elem(i)[t]; 53 | expr pkt_val = net_ctx.pkt2val(in_pkt); 54 | 55 | // Set deq_cnt bounds 56 | snprintf(constr_name, 100, "%s_input_deq_cnt_lb[%d][%d]_%d", id.c_str(), q, t, i); 57 | expr constr_expr = implies(pkt_val, inq->deq_cnt(t) > (int) i); 58 | constr_map.insert(named_constr(constr_name, constr_expr)); 59 | } 60 | } 61 | 62 | // The memcached output queue 63 | Queue* memcached_outq = out_queues[0]; 64 | 65 | unsigned int in_queue_cnt = (unsigned int) in_queues.size(); 66 | vector le_i_gets_j(per_queue_share * in_queue_cnt, net_ctx.bool_val(false)); 67 | for (unsigned int i = 0; i < per_queue_share * in_queue_cnt; i++) { 68 | expr dst_pkt = memcached_outq->enqs(i)[t]; 69 | 70 | expr prev_elems_invalid = net_ctx.bool_val(true); 71 | for (unsigned int j = i; j < per_queue_share * in_queue_cnt; j++) { 72 | unsigned int src_qid = j / per_queue_share; 73 | unsigned int src_elem_id = j % per_queue_share; 74 | 75 | expr src_pkt = in_queues[src_qid]->elem(src_elem_id)[t]; 76 | expr pkt_val = net_ctx.pkt2val(src_pkt); 77 | expr pkt_class = net_ctx.pkt2meta1(src_pkt); 78 | 79 | snprintf(constr_name, 80 | 100, 81 | "%s_memcached_enq[%d]_in[%d][%d]_%d", 82 | id.c_str(), 83 | i, 84 | src_qid, 85 | src_elem_id, 86 | t); 87 | expr cond = (prev_elems_invalid && pkt_val && pkt_class == (int) tenant2_memcached); 88 | expr constr_expr = implies(cond && !le_i_gets_j[j], dst_pkt == src_pkt); 89 | constr_map.insert(named_constr(constr_name, constr_expr)); 90 | 91 | prev_elems_invalid = prev_elems_invalid && 92 | (!pkt_val || pkt_class != (int) tenant2_memcached || 93 | le_i_gets_j[j]); 94 | 95 | le_i_gets_j[j] = le_i_gets_j[j] || cond; 96 | } 97 | 98 | snprintf(constr_name, 100, "%s_memcached_enq[%d]_null_%d", id.c_str(), i, t); 99 | expr constr_expr = implies(prev_elems_invalid, dst_pkt == net_ctx.null_pkt()); 100 | constr_map.insert(named_constr(constr_name, constr_expr)); 101 | } 102 | 103 | // The Spark output queue 104 | Queue* spark_outq = out_queues[1]; 105 | 106 | le_i_gets_j = vector(per_queue_share * in_queue_cnt, net_ctx.bool_val(false)); 107 | for (unsigned int i = 0; i < per_queue_share * in_queue_cnt; i++) { 108 | expr dst_pkt = spark_outq->enqs(i)[t]; 109 | 110 | expr prev_elems_invalid = net_ctx.bool_val(true); 111 | for (unsigned int j = i; j < per_queue_share * in_queue_cnt; j++) { 112 | unsigned int src_qid = j / per_queue_share; 113 | unsigned int src_elem_id = j % per_queue_share; 114 | 115 | expr src_pkt = in_queues[src_qid]->elem(src_elem_id)[t]; 116 | expr pkt_val = net_ctx.pkt2val(src_pkt); 117 | expr pkt_class = net_ctx.pkt2meta1(src_pkt); 118 | 119 | snprintf(constr_name, 120 | 100, 121 | "%s_spark_enq[%d]_in[%d][%d]_%d", 122 | id.c_str(), 123 | i, 124 | src_qid, 125 | src_elem_id, 126 | t); 127 | expr cond = (prev_elems_invalid && pkt_val && 128 | (pkt_class == (int) tenant1_spark || 129 | pkt_class == (int) tenant2_spark)); 130 | expr constr_expr = implies(cond && !le_i_gets_j[j], dst_pkt == src_pkt); 131 | constr_map.insert(named_constr(constr_name, constr_expr)); 132 | 133 | prev_elems_invalid = prev_elems_invalid && (!pkt_val || 134 | (pkt_class != (int) tenant1_spark && 135 | pkt_class != (int) tenant2_spark) || 136 | le_i_gets_j[j]); 137 | 138 | le_i_gets_j[j] = le_i_gets_j[j] || cond; 139 | } 140 | 141 | snprintf(constr_name, 100, "%s_spark_enq[%d]_null_%d", id.c_str(), i, t); 142 | expr constr_expr = implies(prev_elems_invalid, dst_pkt == net_ctx.null_pkt()); 143 | constr_map.insert(named_constr(constr_name, constr_expr)); 144 | } 145 | 146 | // Make sure nothing else gets pushed to the output queue 147 | for (unsigned int q = 0; q < out_queues.size(); q++) { 148 | Queue* outq = out_queues[q]; 149 | for (unsigned int i = per_queue_share * in_queue_cnt; i < outq->max_enq(); i++) { 150 | snprintf(constr_name, 100, "%s_null_rest_of_output_%d_%d_%d", id.c_str(), q, i, t); 151 | expr constr_expr = outq->enqs(i)[t] == net_ctx.null_pkt(); 152 | constr_map.insert(named_constr(constr_name, constr_expr)); 153 | } 154 | } 155 | } 156 | } 157 | 158 | void LoomNICEnqQM::add_constrs(NetContext& net_ctx, map& constr_map) { 159 | constrs_if_not_taken(net_ctx, constr_map); 160 | } 161 | -------------------------------------------------------------------------------- /src/qms/priority_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // priority_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/12/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "priority_qm.hpp" 10 | 11 | PriorityQM::PriorityQM(cid_t id, 12 | unsigned int total_time, 13 | vector in_queue_info, 14 | QueueInfo out_queue_info, 15 | NetContext& net_ctx): 16 | QueuingModule(id, total_time, in_queue_info, vector{out_queue_info}, net_ctx) { 17 | init(net_ctx); 18 | } 19 | 20 | 21 | void PriorityQM::add_proc_vars(NetContext& net_ctx) { 22 | (void) net_ctx; 23 | } 24 | 25 | void PriorityQM::add_constrs(NetContext& net_ctx, map& constr_map) { 26 | char constr_name[100]; 27 | 28 | for (unsigned int t = 0; t < total_time; t++) { 29 | // Find the highest priority queue to pull from 30 | expr not_empty = net_ctx.pkt2val(in_queues[0]->elem(0)[t]); 31 | snprintf(constr_name, 100, "%s_deq_cnt_0_%d", id.c_str(), t); 32 | expr constr_expr = in_queues[0]->deq_cnt(t) == 33 | ite(not_empty, net_ctx.int_val(1), net_ctx.int_val(0)); 34 | 35 | constr_map.insert(named_constr(constr_name, constr_expr)); 36 | 37 | expr higher_empty = !not_empty; 38 | for (unsigned int q = 1; q < in_queues.size(); q++) { 39 | not_empty = net_ctx.pkt2val(in_queues[q]->elem(0)[t]); 40 | snprintf(constr_name, 100, "%s_deq_cnt_%d_%d", id.c_str(), q, t); 41 | expr constr_expr = in_queues[q]->deq_cnt(t) == ite(higher_empty && not_empty, 42 | net_ctx.int_val(1), 43 | net_ctx.int_val(0)); 44 | constr_map.insert(named_constr(constr_name, constr_expr)); 45 | 46 | higher_empty = higher_empty && !not_empty; 47 | } 48 | 49 | // Push to output queue accordingly 50 | Queue* outq = out_queues[0]; 51 | for (unsigned int q = 0; q < in_queues.size(); q++) { 52 | snprintf(constr_name, 100, "%s_output_from_%d_%d", id.c_str(), q, t); 53 | expr constr_expr = implies(in_queues[q]->deq_cnt(t) == 1, 54 | outq->enqs(0)[t] == in_queues[q]->elem(0)[t]); 55 | constr_map.insert(named_constr(constr_name, constr_expr)); 56 | } 57 | 58 | // handle the case where all input queues are empty 59 | expr_vector all_empty(net_ctx.z3_ctx()); 60 | for (unsigned int q = 0; q < in_queues.size(); q++) { 61 | all_empty.push_back(!net_ctx.pkt2val(in_queues[q]->elem(0)[t])); 62 | } 63 | snprintf(constr_name, 100, "%s_all_empty_input_%d", id.c_str(), t); 64 | constr_expr = implies(mk_and(all_empty), outq->enqs(0)[t] == net_ctx.null_pkt()); 65 | constr_map.insert(named_constr(constr_name, constr_expr)); 66 | 67 | // Make sure nothing else gets pushed to the output queue 68 | for (unsigned int i = 1; i < outq->max_enq(); i++) { 69 | snprintf(constr_name, 100, "%s_only_one_output_%d_%d", id.c_str(), i, t); 70 | expr constr_expr = outq->enqs(i)[t] == net_ctx.null_pkt(); 71 | constr_map.insert(named_constr(constr_name, constr_expr)); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/qms/rr_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // rr_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/17/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "rr_qm.hpp" 10 | 11 | RRQM::RRQM(cid_t id, 12 | unsigned int total_time, 13 | vector in_queue_info, 14 | QueueInfo out_queue_info, 15 | NetContext& net_ctx): 16 | QueuingModule(id, total_time, in_queue_info, vector{out_queue_info}, net_ctx) { 17 | last_served_queue_ = new vector[in_queues.size()]; 18 | init(net_ctx); 19 | } 20 | 21 | void RRQM::add_proc_vars(NetContext& net_ctx) { 22 | for (unsigned int q = 0; q < in_queues.size(); q++) { 23 | for (unsigned int t = 0; t < total_time; t++) { 24 | char vname[100]; 25 | snprintf(vname, 100, "%s_last_served_queue[%d][%d]", id.c_str(), q, t); 26 | last_served_queue_[q].push_back(net_ctx.bool_const(vname)); 27 | } 28 | } 29 | } 30 | 31 | void RRQM::add_constrs(NetContext& net_ctx, map& constr_map) { 32 | char constr_name[100]; 33 | unsigned long in_queue_cnt = in_queues.size(); 34 | 35 | 36 | 37 | for (unsigned int q = 0; q < in_queues.size() - 1; q++) { 38 | snprintf(constr_name, 100, "%s_%d_not_lsq_at_0", id.c_str(), q); 39 | expr constr_expr = !last_served_queue_[q][0]; 40 | constr_map.insert(named_constr(constr_name, constr_expr)); 41 | } 42 | snprintf(constr_name, 100, "%s_%d_lsq_at_0", id.c_str(), (unsigned int) in_queues.size() - 1); 43 | expr constr_expr = last_served_queue_[in_queues.size() - 1][0]; 44 | constr_map.insert(named_constr(constr_name, constr_expr)); 45 | 46 | 47 | for (unsigned int t = 0; t < total_time; t++) { 48 | 49 | // find the first non_empty queue after head 50 | // for each value of head 51 | for (unsigned int h = 0; h < in_queue_cnt; h++) { 52 | 53 | unsigned int q = (h + 1) % in_queue_cnt; 54 | expr not_empty = net_ctx.pkt2val(in_queues[q]->elem(0)[t]); 55 | snprintf(constr_name, 100, "%s_head_%d_deq_cnt_%d_%d", id.c_str(), h, q, t); 56 | constr_expr = implies(last_served_queue_[h][t], 57 | in_queues[q]->deq_cnt(t) == 58 | ite(not_empty, net_ctx.int_val(1), net_ctx.int_val(0))); 59 | 60 | constr_map.insert(named_constr(constr_name, constr_expr)); 61 | 62 | expr prev_empty = !not_empty; 63 | 64 | for (unsigned int i = 2; i <= in_queue_cnt; i++) { 65 | q = (h + i) % in_queue_cnt; 66 | 67 | not_empty = net_ctx.pkt2val(in_queues[q]->elem(0)[t]); 68 | snprintf(constr_name, 100, "%s_head_%d_deq_cnt_%d_%d", id.c_str(), h, q, t); 69 | constr_expr = implies(last_served_queue_[h][t], 70 | in_queues[q]->deq_cnt(t) == ite(prev_empty && not_empty, 71 | net_ctx.int_val(1), 72 | net_ctx.int_val(0))); 73 | constr_map.insert(named_constr(constr_name, constr_expr)); 74 | 75 | prev_empty = prev_empty && !not_empty; 76 | } 77 | } 78 | 79 | // Push to output queue accordingly 80 | Queue* outq = out_queues[0]; 81 | for (unsigned int q = 0; q < in_queue_cnt; q++) { 82 | snprintf(constr_name, 100, "%s_output_from_%d_%d", id.c_str(), q, t); 83 | constr_expr = implies(in_queues[q]->deq_cnt(t) == 1, 84 | outq->enqs(0)[t] == in_queues[q]->elem(0)[t]); 85 | constr_map.insert(named_constr(constr_name, constr_expr)); 86 | } 87 | 88 | // handle the case where all input queues are empty 89 | expr_vector all_empty(net_ctx.z3_ctx()); 90 | expr_vector non_empty(net_ctx.z3_ctx()); 91 | for (unsigned int q = 0; q < in_queues.size(); q++) { 92 | all_empty.push_back(!net_ctx.pkt2val(in_queues[q]->elem(0)[t])); 93 | non_empty.push_back(net_ctx.pkt2val(in_queues[q]->elem(0)[t])); 94 | } 95 | snprintf(constr_name, 100, "%s_all_empty_input_%d", id.c_str(), t); 96 | constr_expr = implies(mk_and(all_empty), outq->enqs(0)[t] == net_ctx.null_pkt()); 97 | constr_map.insert(named_constr(constr_name, constr_expr)); 98 | 99 | // Update head 100 | if (t != total_time - 1) { 101 | for (unsigned int q = 0; q < in_queue_cnt; q++) { 102 | snprintf(constr_name, 100, "%s_lsq_%d_at_%d_is_one", id.c_str(), q, t); 103 | constr_expr = implies(in_queues[q]->deq_cnt(t) > 0, last_served_queue_[q][t + 1]); 104 | constr_map.insert(named_constr(constr_name, constr_expr)); 105 | 106 | snprintf(constr_name, 100, "%s_lsq_%d_at_%d_is_zero", id.c_str(), q, t); 107 | constr_expr = implies(in_queues[q]->deq_cnt(t) == 0 && mk_or(non_empty), 108 | !last_served_queue_[q][t + 1]); 109 | constr_map.insert(named_constr(constr_name, constr_expr)); 110 | 111 | snprintf(constr_name, 100, "%s_lsq_%d_at_%d_stays_same", id.c_str(), q, t); 112 | constr_expr = implies(mk_and(all_empty), 113 | last_served_queue_[q][t + 1] == last_served_queue_[q][t]); 114 | constr_map.insert(named_constr(constr_name, constr_expr)); 115 | } 116 | 117 | // TODO: Seems redundant but the solver sometimes likes it 118 | // and sometimes not smh 119 | // for (unsigned int q = 0; q < in_queues.size(); q++){ 120 | // snprintf(constr_name,100, "%s_lsq[%d]_same_%d", id.c_str(), q, t); 121 | // constr_expr = implies(mk_and(all_empty), 122 | // last_served_queue_[q][t + 1] == 123 | // last_served_queue_[q][t]); 124 | // constr_map.insert(named_constr(constr_name, constr_expr)); 125 | // } 126 | } 127 | 128 | 129 | // Make sure nothing else gets pushed to the output queue 130 | for (unsigned int i = 1; i < outq->max_enq(); i++) { 131 | snprintf(constr_name, 100, "%s_only_one_output_%d_%d", id.c_str(), i, t); 132 | expr constr_expr = outq->enqs(i)[t] == net_ctx.null_pkt(); 133 | constr_map.insert(named_constr(constr_name, constr_expr)); 134 | } 135 | } 136 | } 137 | 138 | expr RRQM::last_served_queue(unsigned int q, unsigned int t) { 139 | return last_served_queue_[q][t]; 140 | } 141 | -------------------------------------------------------------------------------- /src/qms/spine_forwarding_qm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // spine_forwarding_qm.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/23/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "spine_forwarding_qm.hpp" 10 | 11 | SpineForwardingQM::SpineForwardingQM(cid_t id, 12 | unsigned int total_time, 13 | unsigned int spine_id, 14 | unsigned int leaf_cnt, 15 | unsigned int servers_per_leaf, 16 | map output_voq_map, 17 | QueueInfo in_queue_info, 18 | vector out_queue_info, 19 | NetContext& net_ctx): 20 | QueuingModule(id, total_time, vector{in_queue_info}, out_queue_info, net_ctx), 21 | spine_id(spine_id), 22 | leaf_cnt(leaf_cnt), 23 | servers_per_leaf(servers_per_leaf), 24 | output_voq_map(output_voq_map) { 25 | init(net_ctx); 26 | } 27 | 28 | 29 | void SpineForwardingQM::add_proc_vars(NetContext& net_ctx) { 30 | (void) net_ctx; 31 | } 32 | 33 | void SpineForwardingQM::add_constrs(NetContext& net_ctx, map& constr_map) { 34 | char constr_name[100]; 35 | 36 | Queue* in_queue = in_queues[0]; 37 | 38 | unsigned int server_cnt = leaf_cnt * servers_per_leaf; 39 | 40 | for (unsigned int t = 0; t < total_time; t++) { 41 | expr in_pkt = in_queue->elem(0)[t]; 42 | expr pkt_val = net_ctx.pkt2val(in_pkt); 43 | expr pkt_dst = net_ctx.pkt2meta1(in_pkt); 44 | 45 | // Set deq_cnt for input queue 46 | snprintf(constr_name, 100, "%s_in_queue_deq_cnt_is_zero_or_one_at_%d", id.c_str(), t); 47 | expr constr_expr = implies(pkt_val, in_queue->deq_cnt(t) == 1) && 48 | implies(!pkt_val, in_queue->deq_cnt(t) == 0); 49 | constr_map.insert(named_constr(constr_name, constr_expr)); 50 | 51 | // Forward 52 | for (unsigned int dst = 0; dst < server_cnt; dst++) { 53 | unsigned int dst_port = dst / servers_per_leaf; 54 | if (output_voq_map.find(dst_port) == output_voq_map.end()) continue; 55 | unsigned int voq_ind = output_voq_map[dst_port]; 56 | snprintf(constr_name, 57 | 100, 58 | "%s_forward_dst_%d_to_port%d(q%d)_at_%d", 59 | id.c_str(), 60 | dst, 61 | dst_port, 62 | voq_ind, 63 | t); 64 | constr_expr = implies(pkt_val && pkt_dst == (int) dst, 65 | out_queues[voq_ind]->enqs(0)[t] == in_pkt); 66 | constr_map.insert(named_constr(constr_name, constr_expr)); 67 | } 68 | 69 | // Don't enqueue into a port if not destined for the port 70 | for (unsigned int i = 0; i < leaf_cnt; i++) { 71 | if (output_voq_map.find(i) == output_voq_map.end()) continue; 72 | unsigned int voq_ind = output_voq_map[i]; 73 | snprintf(constr_name, 100, "%s_no_match_port%d(q%d)_at_%d", id.c_str(), i, voq_ind, t); 74 | constr_expr = implies(pkt_dst < (int) (i * servers_per_leaf) || 75 | pkt_dst >= (int) ((i + 1) * servers_per_leaf), 76 | out_queues[voq_ind]->enqs(0)[t] == net_ctx.null_pkt()); 77 | constr_map.insert(named_constr(constr_name, constr_expr)); 78 | } 79 | 80 | // Flow meta bounds 81 | for (unsigned int q = 0; q < in_queues.size(); q++) { 82 | Queue* queue = in_queues[q]; 83 | for (unsigned int p = 0; p < queue->size(); p++) { 84 | expr pkt = queue->elem(p)[t]; 85 | expr pkt_val = net_ctx.pkt2val(pkt); 86 | expr pkt_meta = net_ctx.pkt2meta2(pkt); 87 | 88 | snprintf(constr_name, 89 | 100, 90 | "%s_flow_meta_bounds_input_queue[%d][%d][%d]", 91 | id.c_str(), 92 | q, 93 | p, 94 | t); 95 | constr_expr = implies(pkt_val, pkt_meta == (int) spine_id); 96 | constr_map.insert(named_constr(constr_name, constr_expr)); 97 | } 98 | } 99 | 100 | for (unsigned int q = 0; q < out_queues.size(); q++) { 101 | Queue* queue = out_queues[q]; 102 | for (unsigned int p = 0; p < queue->size(); p++) { 103 | expr pkt = queue->elem(p)[t]; 104 | expr pkt_val = net_ctx.pkt2val(pkt); 105 | expr pkt_meta = net_ctx.pkt2meta2(pkt); 106 | 107 | snprintf(constr_name, 108 | 100, 109 | "%s_flow_meta_bounds_output_queue[%d][%d][%d]", 110 | id.c_str(), 111 | q, 112 | p, 113 | t); 114 | constr_expr = implies(pkt_val, pkt_meta == (int) spine_id); 115 | constr_map.insert(named_constr(constr_name, constr_expr)); 116 | } 117 | } 118 | 119 | // Don't enqueue into any port if packet is invalid 120 | 121 | for (unsigned int i = 0; i < out_queue_cnt(); i++) { 122 | snprintf(constr_name, 100, "%s_invalid_pkt_port_%d_at_%d", id.c_str(), i, t); 123 | constr_expr = implies(!pkt_val, out_queues[i]->enqs(0)[t] == net_ctx.null_pkt()); 124 | constr_map.insert(named_constr(constr_name, constr_expr)); 125 | } 126 | 127 | // Make sure nothing else gets pushed to the output queue 128 | for (unsigned int i = 0; i < out_queue_cnt(); i++) { 129 | for (unsigned int e = 1; e < out_queues[i]->max_enq(); e++) { 130 | snprintf(constr_name, 100, "%s_out_%d_elem[%d][%d]_is_null", id.c_str(), i, e, t); 131 | expr constr_expr = out_queues[i]->enqs(e)[t] == net_ctx.null_pkt(); 132 | constr_map.insert(named_constr(constr_name, constr_expr)); 133 | } 134 | } 135 | /* 136 | // Bounds on meta3 (arrival time) 137 | for (unsigned int i = 0; i < in_queue_cnt(); i++){ 138 | Queue* queue = in_queues[i]; 139 | for (unsigned int e = 0; e < queue->max_enq(); e++){ 140 | expr pkt = queue->enqs(e)[t]; 141 | expr meta3 = net_ctx.pkt2meta3(pkt); 142 | 143 | snprintf(constr_name,100, "%s_in_%d_enqs[%d][%d]_meta3_bound", id.c_str(), i, e, t); 144 | expr constr_expr = meta3 <= (int) t && meta3 >= 0; 145 | constr_map.insert(named_constr(constr_name, constr_expr)); 146 | } 147 | } 148 | 149 | for (unsigned int i = 0; i < out_queue_cnt(); i++){ 150 | Queue* queue = out_queues[i]; 151 | for (unsigned int e = 0; e < queue->max_enq(); e++){ 152 | expr pkt = queue->enqs(e)[t]; 153 | expr meta3 = net_ctx.pkt2meta3(pkt); 154 | 155 | snprintf(constr_name,100, "%s_out_%d_enqs[%d][%d]_meta3_bound", id.c_str(), i, e, 156 | t); expr constr_expr = meta3 <= (int) t && meta3 >= 0; 157 | constr_map.insert(named_constr(constr_name, constr_expr)); 158 | } 159 | } 160 | */ 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/qms/tbf_qm.cpp: -------------------------------------------------------------------------------- 1 | #include "tbf_qm.hpp" 2 | 3 | TBFQM::TBFQM(cid_t id, 4 | unsigned int total_time, 5 | QueueInfo in_queue_info, 6 | QueueInfo out_queue_info, 7 | NetContext& net_ctx, 8 | TBFInfo info): 9 | QueuingModule(id, 10 | total_time, 11 | std::vector{in_queue_info}, 12 | std::vector{out_queue_info}, 13 | net_ctx) { 14 | init(net_ctx); 15 | this->info = info; 16 | } 17 | 18 | void TBFQM::add_proc_vars(NetContext& net_ctx) { 19 | for (unsigned int t = 0; t < total_time; t++) { 20 | string vname = format_string("%s_token_queue[%d]", id.c_str(), t); 21 | token_queue.push_back(net_ctx.int_const(vname.data())); 22 | } 23 | } 24 | 25 | void TBFQM::add_constrs(NetContext& net_ctx, std::map& constr_map) { 26 | Queue* in_queue = in_queues[0]; 27 | Queue* out_queue = out_queues[0]; 28 | 29 | for (unsigned int t = 1; t < total_time; t++) { 30 | for (unsigned int i = 0; i <= in_queue->size(); i++) { 31 | expr is_last_null_packet = net_ctx.bool_val(true); 32 | if (i > 0) 33 | is_last_null_packet = is_last_null_packet && 34 | net_ctx.pkt2val(in_queue->elem(i - 1)[t]); 35 | if (i < in_queue->size()) 36 | is_last_null_packet = is_last_null_packet && !net_ctx.pkt2val(in_queue->elem(i)[t]); 37 | string constr_name = format_string("%s_deq_count_%d_%d", id.c_str(), t, i); 38 | expr constr_expr = implies(is_last_null_packet, 39 | in_queue->deq_cnt(t) == 40 | min(net_ctx.int_val(i), token_queue[t])); 41 | constr_map.insert(named_constr(constr_name, constr_expr)); 42 | } 43 | } 44 | 45 | for (unsigned int t = 0; t < total_time; t++) { 46 | string constr_name = format_string("%s_tokens_count_%d", id.c_str(), t); 47 | expr constr_expr = net_ctx.bool_val(true); 48 | if (t == 0) 49 | constr_expr = token_queue[t] == 0; 50 | else 51 | constr_expr = token_queue[t] == max(net_ctx.int_val(0), 52 | min(net_ctx.int_val(info.max_tokens), 53 | token_queue[t - 1] + (int) info.link_rate - 54 | in_queue->deq_cnt(t - 1))); 55 | constr_map.insert(named_constr(constr_name, constr_expr)); 56 | } 57 | 58 | for (unsigned int t = 0; t < total_time; t++) { 59 | for (unsigned int i = 0; i < out_queue->max_enq(); ++i) { 60 | string constr_name = format_string("%s_output_from_%d_%d", id.c_str(), i, t); 61 | expr constr_expr = net_ctx.bool_val(true); 62 | constr_expr = ite(in_queue->deq_cnt(t) >= net_ctx.int_val(i + 1), 63 | out_queue->enqs(i)[t] == in_queue->elem(i)[t], 64 | out_queue->enqs(i)[t] == net_ctx.null_pkt()); 65 | constr_map.insert(named_constr(constr_name, constr_expr)); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/query.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // query.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/20/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "query.hpp" 10 | 11 | Query::Query() { 12 | } 13 | 14 | Query::Query(query_quant_t quant, 15 | time_range_t time_range, 16 | query_lhs_t query_lhs, 17 | metric_t metric, 18 | Op op, 19 | unsigned int thresh): 20 | quant(quant), 21 | time_range(time_range), 22 | metric(metric), 23 | lhs(query_lhs), 24 | op(op), 25 | thresh(thresh) { 26 | } 27 | 28 | query_quant_t Query::get_quant() { 29 | return quant; 30 | } 31 | 32 | time_range_t Query::get_time_range() { 33 | return time_range; 34 | } 35 | 36 | metric_t Query::get_metric() { 37 | return metric; 38 | } 39 | 40 | query_lhs_t Query::get_lhs() { 41 | return lhs; 42 | } 43 | 44 | Op Query::get_op() { 45 | return op; 46 | } 47 | 48 | unsigned int Query::get_thresh() { 49 | return thresh; 50 | } 51 | 52 | cid_t Query::get_qid() { 53 | if (holds_alternative(lhs)) { 54 | return get(lhs); 55 | } else if (holds_alternative(lhs)) { 56 | return get(lhs).first; 57 | } else if (holds_alternative(lhs)) { 58 | return get(lhs)[0]; 59 | } 60 | 61 | cout << "Query::get_qid: Invalid query" << endl; 62 | return ""; 63 | } 64 | -------------------------------------------------------------------------------- /src/queuing_module.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // queuing_module.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/9/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "queuing_module.hpp" 10 | 11 | QueuingModule::QueuingModule(cid_t id, 12 | unsigned int total_time, 13 | vector in_queue_info, 14 | vector out_queue_info, 15 | NetContext& net_ctx): 16 | id(id), 17 | total_time(total_time), 18 | out_queue_info(out_queue_info) { 19 | unsigned int qid = 0; 20 | // Instantiate input queues 21 | cid_t base_in_id = id; 22 | 23 | for (unsigned int i = 0; i < in_queue_info.size(); i++) { 24 | QueueInfo qinfo = in_queue_info[i]; 25 | Queue* q; 26 | switch (qinfo.type) { 27 | case queue_t::LINK: { 28 | q = new Link(base_in_id, to_string(qid), total_time, net_ctx); 29 | break; 30 | } 31 | case queue_t::IMM_QUEUE: { 32 | q = new ImmQueue(base_in_id, 33 | to_string(qid), 34 | qinfo.size, 35 | qinfo.max_enq, 36 | qinfo.max_deq, 37 | total_time, 38 | net_ctx); 39 | break; 40 | } 41 | default: { 42 | q = new Queue(base_in_id, 43 | to_string(qid), 44 | qinfo.size, 45 | qinfo.max_enq, 46 | qinfo.max_deq, 47 | total_time, 48 | net_ctx); 49 | break; 50 | } 51 | } 52 | in_queues.push_back(q); 53 | qid++; 54 | } 55 | 56 | // Placeholder pointers for output queues 57 | for (unsigned int i = 0; i < out_queue_info.size(); i++) { 58 | Queue* q = nullptr; 59 | out_queues.push_back(q); 60 | } 61 | } 62 | 63 | void QueuingModule::init(NetContext& net_ctx) { 64 | add_proc_vars(net_ctx); 65 | } 66 | 67 | unsigned long QueuingModule::in_queue_cnt() { 68 | return in_queues.size(); 69 | } 70 | 71 | unsigned long QueuingModule::out_queue_cnt() { 72 | return out_queues.size(); 73 | } 74 | 75 | Queue* QueuingModule::get_in_queue(unsigned int ind) { 76 | return in_queues[ind]; 77 | } 78 | 79 | Queue* QueuingModule::get_out_queue(unsigned int ind) { 80 | return out_queues[ind]; 81 | } 82 | 83 | void QueuingModule::set_out_queue(unsigned int ind, Queue* queue) { 84 | out_queues[ind] = queue; 85 | } 86 | 87 | QueueInfo QueuingModule::get_out_queue_info(unsigned int ind) { 88 | return out_queue_info[ind]; 89 | } 90 | 91 | cid_t QueuingModule::get_id() { 92 | return id; 93 | } 94 | -------------------------------------------------------------------------------- /src/shared_config.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 12/07/22. 6 | // Copyright © 2022 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "shared_config.hpp" 10 | #include 11 | 12 | /******************************* Dists *****************************/ 13 | Dists::Dists(DistsParams params) { 14 | unsigned int seed = params.random_seed; 15 | cout << "seed is: " << seed << endl; 16 | gen.seed(seed); 17 | 18 | real_zero_to_one_dist = uniform_real_distribution(0.0, 1.0); 19 | 20 | rhs_dist = discrete_distribution(begin(params.rhs_selection_weights), 21 | end(params.rhs_selection_weights)); 22 | 23 | rhs_const_dist = uniform_int_distribution(params.rhs_const_min, 24 | params.rhs_const_max); 25 | 26 | rhs_time_coeff_dist = uniform_int_distribution(params.rhs_time_coeff_min, 27 | params.rhs_time_coeff_max); 28 | 29 | trf_dist = discrete_distribution(begin(params.trf_selection_weights), 30 | end(params.trf_selection_weights)); 31 | 32 | 33 | wl_metric_dist = discrete_distribution(begin(params.wl_metric_selection_weights), 34 | end(params.wl_metric_selection_weights)); 35 | 36 | input_queue_dist = uniform_int_distribution(0, params.in_queue_cnt - 1); 37 | input_queue_cnt_dist = uniform_int_distribution(0, params.in_queue_cnt + 1); 38 | 39 | op_dist = uniform_int_distribution(params.op_range_min, params.op_range_max); 40 | 41 | timestep_dist = uniform_int_distribution(0, params.total_time - 1); 42 | 43 | enq_dist = uniform_int_distribution(params.enq_range_min, params.enq_range_max); 44 | 45 | pkt_meta1_val_dist = uniform_int_distribution(0, params.pkt_meta1_val_max); 46 | pkt_meta2_val_dist = uniform_int_distribution(0, params.pkt_meta2_val_max); 47 | } 48 | 49 | mt19937& Dists::get_gen() { 50 | return gen; 51 | } 52 | 53 | double Dists::real_zero_to_one() { 54 | return real_zero_to_one_dist(gen); 55 | } 56 | 57 | unsigned int Dists::rhs() { 58 | return rhs_dist(gen); 59 | } 60 | 61 | unsigned int Dists::rhs_const() { 62 | return rhs_const_dist(gen); 63 | } 64 | unsigned int Dists::rhs_time_coeff() { 65 | return rhs_time_coeff_dist(gen); 66 | } 67 | 68 | unsigned int Dists::trf() { 69 | return trf_dist(gen); 70 | } 71 | 72 | metric_t Dists::wl_metric() { 73 | return (metric_t) wl_metric_dist(gen); 74 | } 75 | 76 | unsigned int Dists::input_queue() { 77 | return input_queue_dist(gen); 78 | } 79 | unsigned int Dists::input_queue_cnt() { 80 | return input_queue_cnt_dist(gen); 81 | } 82 | 83 | Op Dists::op() { 84 | Op::Type type = (Op::Type) op_dist(gen); 85 | return Op(type); 86 | } 87 | 88 | unsigned int Dists::timestep() { 89 | return timestep_dist(gen); 90 | } 91 | unsigned int Dists::enq() { 92 | return enq_dist(gen); 93 | } 94 | 95 | unsigned int Dists::pkt_metric1_val() { 96 | return pkt_meta1_val_dist(gen); 97 | } 98 | unsigned int Dists::pkt_metric2_val() { 99 | return pkt_meta2_val_dist(gen); 100 | } 101 | 102 | uniform_int_distribution& Dists::get_pkt_meta1_val_dist() { 103 | return pkt_meta1_val_dist; 104 | } 105 | 106 | uniform_int_distribution& Dists::get_pkt_meta2_val_dist() { 107 | return pkt_meta2_val_dist; 108 | } 109 | 110 | uniform_int_distribution& Dists::get_rhs_const_dist() { 111 | return rhs_const_dist; 112 | } 113 | 114 | /******************************* SharedConfig *****************************/ 115 | 116 | SharedConfig::SharedConfig(unsigned int total_time, 117 | unsigned int in_queue_cnt, 118 | qset_t target_queues, 119 | Dists* dists): 120 | total_time(total_time), 121 | in_queue_cnt(in_queue_cnt), 122 | target_queues(target_queues), 123 | dists(dists) { 124 | } 125 | 126 | unsigned int SharedConfig::get_total_time() { 127 | return total_time; 128 | } 129 | 130 | unsigned int SharedConfig::get_in_queue_cnt() { 131 | return in_queue_cnt; 132 | } 133 | 134 | qset_t SharedConfig::get_target_queues() { 135 | return target_queues; 136 | } 137 | 138 | Dists* SharedConfig::get_dists() { 139 | return dists; 140 | } 141 | -------------------------------------------------------------------------------- /src/solver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // solver.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 2/3/21. 6 | // Copyright © 2021 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "solver.hpp" 10 | 11 | unsigned long long int Solver::get_check_workload_without_query_max_time() { 12 | return check_workload_without_query_max_time; 13 | } 14 | 15 | unsigned long long int Solver::get_check_workload_without_query_avg_time() { 16 | return check_workload_without_query_total_invoc == 0 17 | ? 0 18 | : check_workload_without_query_total_time / check_workload_without_query_total_invoc; 19 | } 20 | 21 | unsigned long long int Solver::get_check_workload_with_query_max_time() { 22 | return check_workload_with_query_max_time; 23 | } 24 | 25 | unsigned long long int Solver::get_check_workload_with_query_avg_time() { 26 | return check_workload_with_query_total_invoc == 0 27 | ? 0 28 | : check_workload_with_query_total_time / check_workload_with_query_total_invoc; 29 | } 30 | 31 | ostream& operator<<(ostream& os, const solver_res_t& res) { 32 | switch (res) { 33 | case solver_res_t::SAT: os << "SAT"; break; 34 | case solver_res_t::UNSAT: os << "UNSAT"; break; 35 | default: os << "UNKNOWN"; break; 36 | } 37 | return os; 38 | } 39 | -------------------------------------------------------------------------------- /src/spec_factory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // workload.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/19/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "spec_factory.hpp" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "util.hpp" 17 | 18 | SpecFactory::SpecFactory(SharedConfig* shared_config): dists(shared_config->get_dists()) { 19 | total_time = shared_config->get_total_time(); 20 | in_queue_cnt = shared_config->get_in_queue_cnt(); 21 | target_queues = shared_config->get_target_queues(); 22 | 23 | initializeSpecs(); 24 | } 25 | 26 | RandomSpecGenerationParameters SpecFactory::get_metric_params(metric_t metric_type) { 27 | switch (metric_type) { 28 | case metric_t::DST: return {false, dists->get_pkt_meta1_val_dist()}; 29 | case metric_t::ECMP: return {false, dists->get_pkt_meta2_val_dist()}; 30 | default: return {true, dists->get_rhs_const_dist()}; 31 | } 32 | } 33 | 34 | void SpecFactory::initializeSpecs() { 35 | SpecFactory::spec_generators.clear(); 36 | 37 | SpecGeneratorFuncPtr comp_ptr = &SpecFactory::random_comp; 38 | SpecFactory::spec_generators.push_back(comp_ptr); 39 | } 40 | 41 | //************************************* TimedSpec *************************************// 42 | 43 | TimedSpec SpecFactory::random_timed_spec() { 44 | WlSpec* wl_spec = random_wl_spec(); 45 | 46 | unsigned int time_range_lb = dists->timestep(); 47 | unsigned int time_range_ub = dists->timestep(); 48 | while (time_range_ub < time_range_lb) { 49 | time_range_lb = dists->timestep(); 50 | time_range_ub = dists->timestep(); 51 | } 52 | 53 | return TimedSpec(wl_spec, time_range_t(time_range_lb, time_range_ub), total_time); 54 | } 55 | 56 | 57 | void SpecFactory::pick_neighbors(TimedSpec& spec, vector& neighbors) { 58 | WlSpec* wl_spec = spec.get_wl_spec(); 59 | time_range_t time_range = spec.get_time_range(); 60 | 61 | // Changing wl_spec 62 | vector wl_spec_neighbors; 63 | pick_neighbors(wl_spec, wl_spec_neighbors); 64 | for (unsigned int i = 0; i < wl_spec_neighbors.size(); i++) { 65 | TimedSpec nei = TimedSpec(wl_spec_neighbors[i], time_range, total_time); 66 | if (!nei.spec_is_empty() && !nei.spec_is_all()) { 67 | neighbors.push_back(nei); 68 | } 69 | } 70 | 71 | // changing time 72 | 73 | mt19937& gen = dists->get_gen(); 74 | // change lb 75 | if (time_range.second > 0) { 76 | uniform_int_distribution lb_dist(0, time_range.second); 77 | time_range_t time_range_neighbor(lb_dist(gen), time_range.second); 78 | while (time_range_neighbor == time_range) { 79 | time_range_neighbor = time_range_t(lb_dist(gen), time_range.second); 80 | } 81 | TimedSpec nei = TimedSpec(wl_spec, time_range_neighbor, total_time); 82 | neighbors.push_back(nei); 83 | } 84 | 85 | if (time_range.first < total_time - 1) { 86 | uniform_int_distribution ub_dist(time_range.first, total_time - 1); 87 | time_range_t time_range_neighbor(time_range.first, ub_dist(gen)); 88 | while (time_range_neighbor == time_range) { 89 | time_range_neighbor = time_range_t(time_range.first, ub_dist(gen)); 90 | } 91 | TimedSpec nei = TimedSpec(wl_spec, time_range_neighbor, total_time); 92 | neighbors.push_back(nei); 93 | } 94 | } 95 | 96 | //************************************* WlSpec *************************************// 97 | 98 | WlSpec* SpecFactory::random_wl_spec() { 99 | mt19937& gen = dists->get_gen(); 100 | uniform_int_distribution<> dist(0, spec_generators.size() - 1); 101 | int index = dist(gen); 102 | return (this->*spec_generators[index])(); 103 | } 104 | 105 | void SpecFactory::pick_neighbors(WlSpec* spec, std::vector& neighbors) { 106 | Comp* compSpec = dynamic_cast(spec); 107 | if (compSpec) { 108 | vector comp_neighbors; 109 | pick_neighbors(*compSpec, comp_neighbors); 110 | for (const Comp& neighbor : comp_neighbors) { 111 | neighbors.push_back(new Comp(neighbor)); 112 | } 113 | } 114 | } 115 | 116 | //************************************* COMP *************************************// 117 | 118 | WlSpec* SpecFactory::random_comp() { 119 | Comp* res; 120 | 121 | do { 122 | MExpr* lhs = random_m_expr(); 123 | Expr* rhs = random_rhs(); 124 | const Indiv* indiv = dynamic_cast(lhs); 125 | if (indiv) { 126 | metric_t metric = indiv->get_metric(); 127 | rhs = random_rhs(get_metric_params(metric)); 128 | } 129 | Op op = random_op(); 130 | res = new Comp(lhs, op, rhs); 131 | } while (res->spec_is_empty() || res->spec_is_all()); 132 | 133 | return res; 134 | } 135 | 136 | void SpecFactory::pick_neighbors(Comp& spec, vector& neighbors) { 137 | MExpr* lhs = spec.get_lhs(); 138 | Op op = spec.get_op(); 139 | Expr* rhs = spec.get_rhs(); 140 | 141 | // Changing lhs 142 | vector lhs_neighbors; 143 | pick_m_expr_neighbors(lhs, lhs_neighbors); 144 | for (unsigned int i = 0; i < lhs_neighbors.size(); i++) { 145 | Comp nei = Comp(lhs_neighbors[i], op, rhs); 146 | if (!nei.spec_is_empty() && !nei.spec_is_all()) { 147 | neighbors.push_back(nei); 148 | } 149 | } 150 | 151 | // Changing op 152 | Op new_op = random_op(); 153 | while (new_op == op) { 154 | new_op = random_op(); 155 | } 156 | Comp nei = Comp(lhs, new_op, rhs); 157 | if (!nei.spec_is_empty() && !nei.spec_is_all()) { 158 | neighbors.push_back(nei); 159 | } 160 | 161 | // Changing rhs 162 | vector rhs_neighbors; 163 | const Indiv* indiv = dynamic_cast(lhs); 164 | if (indiv) { 165 | metric_t metric = indiv->get_metric(); 166 | pick_rhs_neighbors(rhs, rhs_neighbors, get_metric_params(metric)); 167 | } else { 168 | pick_rhs_neighbors(rhs, rhs_neighbors); 169 | } 170 | for (unsigned int i = 0; i < rhs_neighbors.size(); i++) { 171 | Comp nei = Comp(lhs, op, rhs_neighbors[i]); 172 | if (!nei.spec_is_empty() && !nei.spec_is_all()) { 173 | neighbors.push_back(nei); 174 | } 175 | } 176 | } 177 | 178 | //************************************* RHS *************************************// 179 | 180 | Expr* SpecFactory::random_rhs() { 181 | return random_rhs({true, dists->get_rhs_const_dist()}); 182 | } 183 | 184 | Expr* SpecFactory::random_rhs(RandomSpecGenerationParameters params) { 185 | unsigned int rhs_type = dists->rhs(); 186 | while (rhs_type == 0) { 187 | rhs_type = dists->rhs(); 188 | } 189 | 190 | if (params.time_valid && rhs_type == 1) { 191 | Time time = random_time(); 192 | return new Time(time); 193 | } 194 | 195 | mt19937& gen = dists->get_gen(); 196 | unsigned int c = params.const_dist(gen); 197 | return new Constant(c); 198 | } 199 | 200 | void SpecFactory::pick_rhs_neighbors(Expr* rhs, vector& neighbors) { 201 | pick_rhs_neighbors(rhs, neighbors, {true, dists->get_rhs_const_dist(), false}); 202 | } 203 | 204 | void SpecFactory::pick_rhs_neighbors(Expr* rhs, 205 | vector& neighbors, 206 | RandomSpecGenerationParameters params) { 207 | MExpr* mexpr = dynamic_cast(rhs); 208 | if (mexpr) { 209 | vector trf_neighbors; 210 | pick_m_expr_neighbors(mexpr, trf_neighbors); 211 | for (const MExpr* neighbor : trf_neighbors) { 212 | neighbors.push_back(new MExpr(*neighbor)); 213 | } 214 | } 215 | Time* time = dynamic_cast(rhs); 216 | if (time) { 217 | Time time_neighbor = random_time(); 218 | while (time_neighbor == *time) { 219 | time_neighbor = random_time(); 220 | } 221 | neighbors.push_back(new Time(time_neighbor)); 222 | 223 | unsigned int c = time->get_coeff(); 224 | if (params.bound_with_dist) { 225 | if (c > params.const_dist.max()) c = params.const_dist.max(); 226 | if (c < params.const_dist.min()) c = params.const_dist.min(); 227 | } 228 | neighbors.push_back(new Constant(c)); 229 | } 230 | Constant* c = dynamic_cast(rhs); 231 | if (c) { 232 | mt19937& gen = dists->get_gen(); 233 | unsigned int c_val = c->get_value(); 234 | unsigned int c_neighbor = params.const_dist(gen); 235 | while (c_neighbor == c_val) { 236 | c_neighbor = params.const_dist(gen); 237 | } 238 | neighbors.push_back(new Constant(c_neighbor)); 239 | 240 | if (params.time_valid) { 241 | neighbors.push_back(new Time(1u)); 242 | } 243 | } 244 | } 245 | 246 | //************************************* TRF *************************************// 247 | 248 | MExpr* SpecFactory::random_m_expr() { 249 | unsigned int trf_type = dists->trf(); 250 | if (target_queues.size() < 2) trf_type = 1; 251 | switch (trf_type) { 252 | case 0: return new QSum(random_qsum()); 253 | default: return new Indiv(random_indiv()); 254 | } 255 | } 256 | 257 | void SpecFactory::pick_m_expr_neighbors(MExpr* m_expr, vector& neighbors) { 258 | QSum* qsum = dynamic_cast(m_expr); 259 | if (qsum) { 260 | pick_neighbors(*qsum, neighbors); 261 | } 262 | Indiv* indiv = dynamic_cast(m_expr); 263 | if (indiv) { 264 | pick_neighbors(*indiv, neighbors); 265 | } 266 | } 267 | 268 | //************************************* QSUM *************************************// 269 | 270 | qset_t SpecFactory::random_qsum_qset() { 271 | qset_t res; 272 | unsigned int cnt = dists->input_queue_cnt(); 273 | while (cnt < 2 || cnt > target_queues.size()) { 274 | cnt = dists->input_queue_cnt(); 275 | } 276 | 277 | while (res.size() < cnt) { 278 | unsigned int q = dists->input_queue(); 279 | 280 | while (target_queues.find(q) == target_queues.end()) { 281 | q = dists->input_queue(); 282 | } 283 | 284 | res.insert(q); 285 | } 286 | return res; 287 | } 288 | 289 | QSum SpecFactory::random_qsum() { 290 | // TODO: generalize this to aggregatable metrics 291 | metric_t metric = metric_t::CENQ; 292 | qset_t qset = random_qsum_qset(); 293 | return QSum(qset, metric); 294 | } 295 | 296 | 297 | void SpecFactory::pick_neighbors(QSum& qsum, vector& neighbors) { 298 | // TODO: change metric, when there is more than one aggregatable metric 299 | 300 | // changing qset 301 | qset_t qset = qsum.qset; 302 | // add one to qset 303 | unsigned int max_size = target_queues.size(); 304 | if (qset.size() < max_size) { 305 | qset_t qset_neighbor = qset; 306 | while (qset_neighbor.size() == qset.size()) { 307 | unsigned int q = dists->input_queue(); 308 | 309 | while (target_queues.find(q) == target_queues.end()) { 310 | q = dists->input_queue(); 311 | } 312 | 313 | qset_neighbor.insert(q); 314 | } 315 | neighbors.push_back(new QSum(qset_neighbor, qsum.metric)); 316 | } 317 | 318 | // remove one from qset 319 | uniform_int_distribution dist(0, (unsigned int) qset.size() - 1); 320 | qset_t::iterator it = qset.begin(); 321 | mt19937& gen = dists->get_gen(); 322 | advance(it, dist(gen)); 323 | if (qset.size() == 2) { 324 | neighbors.push_back(new Indiv(qsum.metric, *it)); 325 | } else { 326 | qset_t qset_neighbor = qset; 327 | qset_neighbor.erase(*it); 328 | neighbors.push_back(new QSum(qset_neighbor, qsum.metric)); 329 | } 330 | } 331 | 332 | //************************************* INDIV *************************************// 333 | 334 | Indiv SpecFactory::random_indiv() { 335 | metric_t metric = dists->wl_metric(); 336 | unsigned int queue = dists->input_queue(); 337 | 338 | while (target_queues.find(queue) == target_queues.end()) { 339 | queue = dists->input_queue(); 340 | } 341 | return Indiv(metric, queue); 342 | } 343 | 344 | void SpecFactory::pick_neighbors(Indiv& indiv, vector& neighbors) { 345 | // TODO: change metric? 346 | 347 | // changing queue 348 | unsigned int queue_neighbor = dists->input_queue(); 349 | while ((queue_neighbor == indiv.get_queue() && target_queues.size() > 1) || 350 | target_queues.find(queue_neighbor) == target_queues.end()) { 351 | queue_neighbor = dists->input_queue(); 352 | } 353 | neighbors.push_back(new Indiv(indiv.get_metric(), queue_neighbor)); 354 | } 355 | 356 | //************************************* TIME *************************************// 357 | 358 | Time SpecFactory::random_time() { 359 | unsigned int random_coeff = dists->rhs_time_coeff(); 360 | return Time(random_coeff); 361 | } 362 | 363 | //************************************* COMP *************************************// 364 | Op SpecFactory::random_op() { 365 | return dists->op(); 366 | } 367 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // util.cpp 3 | // FPerf 4 | // 5 | // Created by Mina Tahmasbi Arashloo on 11/12/20. 6 | // Copyright © 2020 Mina Tahmasbi Arashloo. All rights reserved. 7 | // 8 | 9 | #include "util.hpp" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | //************************************* QSET *************************************// 16 | bool is_superset(qset_t qset1, qset_t qset2) { 17 | set res; 18 | set_difference( 19 | qset2.begin(), qset2.end(), qset1.begin(), qset1.end(), inserter(res, res.begin())); 20 | return res.size() == 0; 21 | } 22 | 23 | ostream& operator<<(ostream& os, const qset_t& qset) { 24 | os << "{"; 25 | for (qset_t::iterator it = qset.begin(); it != qset.end(); it++) { 26 | os << *it << ", "; 27 | } 28 | os << "}"; 29 | return os; 30 | } 31 | 32 | bool satisfies(unsigned int q, qset_t qset) { 33 | return qset.find(q) != qset.end(); 34 | } 35 | 36 | 37 | //************************************* CID *************************************// 38 | 39 | cid_t get_unique_id(cid_t module_id, cid_t queue_id) { 40 | return module_id + "." + queue_id; 41 | } 42 | 43 | //************************************* COMP *************************************// 44 | 45 | Op::Op() { 46 | } 47 | Op::Op(Op::Type op): type(op) { 48 | } 49 | 50 | Op::Type Op::get_type() const { 51 | return type; 52 | } 53 | 54 | ostream& operator<<(ostream& os, const Op& op) { 55 | switch (op.get_type()) { 56 | case Op::Type::GT: os << ">"; break; 57 | case Op::Type::GE: os << ">="; break; 58 | case Op::Type::LT: os << "<"; break; 59 | case Op::Type::LE: os << "<="; break; 60 | case Op::Type::EQ: os << "=="; break; 61 | } 62 | return os; 63 | } 64 | 65 | bool Op::eval(unsigned int lhs_val, const Op& op, unsigned int rhs_val) { 66 | switch (op.get_type()) { 67 | case Type::GT: return lhs_val > rhs_val; 68 | case Type::GE: return lhs_val >= rhs_val; 69 | case Type::LT: return lhs_val < rhs_val; 70 | case Type::LE: return lhs_val <= rhs_val; 71 | case Type::EQ: return lhs_val == rhs_val; 72 | default: throw std::invalid_argument("Unknown operation"); 73 | } 74 | } 75 | 76 | void Op::neg() { 77 | switch (type) { 78 | case Type::GT: type = Type::LE; break; 79 | case Type::GE: type = Type::LT; break; 80 | case Type::LT: type = Type::GE; break; 81 | case Type::LE: type = Type::GT; break; 82 | case Type::EQ: break; 83 | default: throw std::invalid_argument("Unknown operation"); 84 | } 85 | } 86 | 87 | bool Op::operator==(const Op& other) const { 88 | return type == other.type; 89 | } 90 | 91 | bool Op::operator<(const Op& other) const { 92 | return type < other.type; 93 | } 94 | 95 | //************************************* TIME RANGE *************************************// 96 | bool is_superset(time_range_t t1, time_range_t t2) { 97 | return t1.first <= t2.first && t1.second >= t2.second; 98 | } 99 | 100 | bool includes(time_range_t time_range, unsigned int t) { 101 | bool res = time_range.first <= t && t <= time_range.second; 102 | return res; 103 | } 104 | 105 | ostream& operator<<(ostream& os, const time_range_t& time_range) { 106 | os << "[" << (time_range.first + 1) << ", " << (time_range.second + 1) << "]"; 107 | return os; 108 | } 109 | //************************************* TIME *************************************// 110 | 111 | time_typ noww() { 112 | return chrono::high_resolution_clock::now(); 113 | } 114 | 115 | unsigned long long int get_diff_sec(time_typ start, time_typ end) { 116 | auto duration = chrono::duration_cast(end - start); 117 | return duration.count(); 118 | } 119 | 120 | unsigned long long int get_diff_millisec(time_typ start, time_typ end) { 121 | auto duration = chrono::duration_cast(end - start); 122 | return duration.count(); 123 | } 124 | 125 | unsigned long long int get_diff_microsec(time_typ start, time_typ end) { 126 | auto duration = chrono::duration_cast(end - start); 127 | return duration.count(); 128 | } 129 | 130 | //************************************* OTHER *************************************// 131 | string banner(string b) { 132 | stringstream ss; 133 | ss << "**********************************************"; 134 | ss << "**********************************************" << endl; 135 | ss << "**********************************************"; 136 | ss << "**********************************************" << endl; 137 | ss << b << endl; 138 | ss << "**********************************************"; 139 | ss << "**********************************************" << endl; 140 | ss << "**********************************************"; 141 | ss << "**********************************************" << endl; 142 | return ss.str(); 143 | } 144 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include "rr_scheduler_test.hpp" 2 | #include "search_test.hpp" 3 | #include "tbf_test.hpp" 4 | #include "test_runner.hpp" 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main(int argc, char** argv) { 10 | 11 | vector arguments(argv + 1, argv + argc); 12 | 13 | TestRunner runner; 14 | 15 | RRSchedulerTest rrSchedulerTest; 16 | rrSchedulerTest.add_to_runner(&runner); 17 | 18 | TBFTest tbfTest; 19 | tbfTest.add_to_runner(&runner); 20 | 21 | 22 | SearchTest searchTest; 23 | searchTest.add_to_runner(&runner); 24 | 25 | bool result = runner.run(arguments); 26 | 27 | cout << runner.get_report(); 28 | 29 | return !result; 30 | } 31 | -------------------------------------------------------------------------------- /tests/rr_scheduler_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rr_scheduler.hpp" 4 | #include "rr_scheduler_test.hpp" 5 | 6 | bool test_unsat_query() { 7 | unsigned int in_queue_cnt = 5; 8 | unsigned int period = 5; 9 | unsigned int recur = 2; 10 | 11 | unsigned int total_time = recur * period; 12 | 13 | RRScheduler *rr = new RRScheduler(in_queue_cnt, total_time); 14 | 15 | unsigned int queue1 = 1; 16 | unsigned int queue2 = 2; 17 | 18 | Workload wl(100, in_queue_cnt, total_time); 19 | 20 | for (unsigned int q = 0; q < in_queue_cnt; q++) { 21 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, q), Op(Op::Type::GE), new Time(1)), time_range_t(0, total_time - 1), total_time)); 22 | } 23 | 24 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, queue1), Op(Op::Type::GT), new Indiv(metric_t::CENQ, queue2)), time_range_t(total_time - 1, total_time - 1), total_time)); 25 | 26 | cout << "base workload: " << endl << wl << endl; 27 | 28 | rr->set_base_workload(wl); 29 | 30 | // Query 31 | cid_t queue1_id = rr->get_in_queues()[queue1]->get_id(); 32 | cid_t queue2_id = rr->get_in_queues()[queue2]->get_id(); 33 | 34 | Query query(query_quant_t::FORALL, 35 | time_range_t(total_time - 1 - (period - 1), total_time - 1), 36 | qdiff_t(queue2_id, queue1_id), metric_t::CDEQ, Op(Op::Type::GE), 3); 37 | 38 | rr->set_query(query); 39 | 40 | solver_res_t result = rr->satisfy_query(); 41 | 42 | cout << result << endl; 43 | 44 | return result == solver_res_t::UNSAT; 45 | } 46 | 47 | bool test_sat_query() { 48 | unsigned int in_queue_cnt = 5; 49 | unsigned int period = 5; 50 | unsigned int recur = 2; 51 | unsigned int rate = 4; 52 | 53 | unsigned int total_time = recur * period; 54 | 55 | RRScheduler *rr = new RRScheduler(in_queue_cnt, total_time); 56 | 57 | unsigned int queue1 = 1; 58 | unsigned int queue2 = 2; 59 | 60 | Workload wl(100, in_queue_cnt, total_time); 61 | 62 | for (unsigned int i = 1; i <= recur; i++) { 63 | for (unsigned int q = 0; q < in_queue_cnt; q++) { 64 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, q), Op(Op::Type::GE), new Constant(i * rate)), time_range_t(i * period - 1, i * period - 1), total_time)); 65 | } 66 | } 67 | 68 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, queue1), Op(Op::Type::GT), new Indiv(metric_t::CENQ, queue2)), time_range_t(total_time - 1, total_time - 1), total_time)); 69 | 70 | cout << "base workload: " << endl << wl << endl; 71 | 72 | rr->set_base_workload(wl); 73 | 74 | // Query 75 | cid_t queue1_id = rr->get_in_queues()[queue1]->get_id(); 76 | cid_t queue2_id = rr->get_in_queues()[queue2]->get_id(); 77 | 78 | Query query(query_quant_t::FORALL, 79 | time_range_t(total_time - 1 - (period - 1), total_time - 1), 80 | qdiff_t(queue2_id, queue1_id), metric_t::CDEQ, Op(Op::Type::GE), 3); 81 | 82 | rr->set_query(query); 83 | 84 | solver_res_t result = rr->satisfy_query(); 85 | 86 | cout << result << endl; 87 | 88 | return result == solver_res_t::SAT; 89 | } 90 | 91 | void RRSchedulerTest::add_to_runner(TestRunner *runner) { 92 | runner->add_test_case("rr_unsat", test_sat_query); 93 | runner->add_test_case("rr_sat", test_unsat_query); 94 | } 95 | -------------------------------------------------------------------------------- /tests/rr_scheduler_test.hpp: -------------------------------------------------------------------------------- 1 | #include "test_class.hpp" 2 | class RRSchedulerTest : TestClass { 3 | public: 4 | void add_to_runner(TestRunner * runner) override; 5 | }; -------------------------------------------------------------------------------- /tests/search_test.cpp: -------------------------------------------------------------------------------- 1 | #include "search_test.hpp" 2 | #include "iostream" 3 | #include "params.hpp" 4 | #include "query.hpp" 5 | #include "rr_scheduler.hpp" 6 | #include "search.hpp" 7 | #include "simple_cp.hpp" 8 | #include "tests.hpp" 9 | 10 | bool test_search() { 11 | uint total_time = 5; 12 | uint last_t = total_time - 1; 13 | 14 | SimpleCP *ss = new SimpleCP(total_time); 15 | 16 | Workload wl(100, 1, total_time); 17 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, 0), Op(Op::Type::LE), new Constant((uint)1)), time_range_t(last_t, last_t), total_time)); 18 | ss->set_base_workload(wl); 19 | 20 | // Query 21 | cid_t queue_id = ss->get_in_queue()->get_id(); 22 | 23 | Query query(query_quant_t::FORALL, time_range_t(last_t, last_t), queue_id, 24 | metric_t::CDEQ, Op(Op::Type::GE), 1); 25 | 26 | ss->set_query(query); 27 | 28 | ss->satisfy_query(); 29 | 30 | IndexedExample *base_eg = new IndexedExample(); 31 | qset_t target_queues; 32 | 33 | if (!ss->generate_base_example(base_eg, target_queues, 1)) 34 | return false; 35 | 36 | DistsParams dists_params; 37 | dists_params.in_queue_cnt = ss->in_queue_cnt(); 38 | dists_params.total_time = total_time; 39 | dists_params.pkt_meta1_val_max = 1; 40 | dists_params.pkt_meta2_val_max = 1; 41 | dists_params.random_seed = 7000; 42 | Dists *dists = new Dists(dists_params); 43 | SharedConfig *config = new SharedConfig(total_time, 1, target_queues, dists); 44 | 45 | if (!ss->set_shared_config(config)) 46 | return false; 47 | 48 | deque good_examples; 49 | ss->generate_good_examples2(base_eg, 50, good_examples); 50 | 51 | deque bad_examples; 52 | ss->generate_bad_examples(50, bad_examples); 53 | 54 | Search search(ss, query, 10, config, good_examples, bad_examples); 55 | search.run(); 56 | 57 | return true; 58 | } 59 | 60 | void SearchTest::add_to_runner(TestRunner *runner) { 61 | runner->add_test_case("search", test_search); 62 | } 63 | -------------------------------------------------------------------------------- /tests/search_test.hpp: -------------------------------------------------------------------------------- 1 | #include "test_class.hpp" 2 | class SearchTest : TestClass { 3 | public: 4 | void add_to_runner(TestRunner *runner) override; 5 | }; 6 | -------------------------------------------------------------------------------- /tests/simple_cp.cpp: -------------------------------------------------------------------------------- 1 | #include "simple_cp.hpp" 2 | 3 | #include "rr_qm.hpp" 4 | 5 | #include 6 | 7 | SimpleCP::SimpleCP(unsigned int total_time) : ContentionPoint(total_time) { 8 | init(); 9 | } 10 | 11 | void SimpleCP::add_nodes() { 12 | QueueInfo info; 13 | info.size = MAX_QUEUE_SIZE; 14 | info.max_enq = 4; 15 | info.max_deq = 2; 16 | info.type = queue_t::QUEUE; 17 | 18 | cid_t m_id = "SimpleQM"; 19 | 20 | SimpleQM *qm = new SimpleQM(m_id, total_time, info, net_ctx); 21 | 22 | nodes.push_back(m_id); 23 | id_to_qm[m_id] = qm; 24 | } 25 | 26 | Queue *SimpleCP::get_in_queue() { return in_queues[0]; } 27 | 28 | Queue *SimpleCP::get_out_queue() { return out_queues[0]; } 29 | 30 | void SimpleCP::add_edges() {} 31 | 32 | void SimpleCP::add_metrics() { 33 | for (unsigned int q = 0; q < in_queues.size(); q++) { 34 | Queue *queue = in_queues[q]; 35 | CEnq *ce = new CEnq(queue, total_time, net_ctx); 36 | cenq.push_back(ce); 37 | metrics[metric_t::CENQ][queue->get_id()] = ce; 38 | queue->add_metric(metric_t::CENQ, ce); 39 | } 40 | 41 | for (unsigned int q = 0; q < in_queues.size(); q++) { 42 | Queue *queue = in_queues[q]; 43 | CDeq *cd = new CDeq(queue, total_time, net_ctx); 44 | cdeq.push_back(cd); 45 | metrics[metric_t::CDEQ][queue->get_id()] = cd; 46 | queue->add_metric(metric_t::CDEQ, cd); 47 | } 48 | 49 | for (unsigned int q = 0; q < in_queues.size(); q++){ 50 | Queue* queue = in_queues[q]; 51 | AIPG* g = new AIPG(queue, total_time, net_ctx); 52 | aipg.push_back(g); 53 | metrics[metric_t::AIPG][queue->get_id()] = g; 54 | queue->add_metric(metric_t::AIPG, g); 55 | } 56 | } 57 | 58 | string SimpleCP::cp_model_str(model &m, NetContext &net_ctx, 59 | unsigned int t) { 60 | (void) m; 61 | (void) net_ctx; 62 | (void) t; 63 | return ""; 64 | } 65 | 66 | SimpleQM::SimpleQM(cid_t id, unsigned int total_time, QueueInfo queue_info, 67 | NetContext &net_ctx) 68 | : QueuingModule(id, total_time, vector{queue_info}, 69 | vector{queue_info}, net_ctx) { 70 | init(net_ctx); 71 | } 72 | 73 | void SimpleQM::add_proc_vars(NetContext &net_ctx) { (void) net_ctx; } 74 | 75 | void SimpleQM::add_constrs(NetContext &net_ctx, 76 | map &constr_map) { 77 | 78 | Queue *in_queue = in_queues[0]; 79 | Queue *out_queue = out_queues[0]; 80 | 81 | for (unsigned int t = 0; t < total_time; t++) { 82 | string constr_name = format_string("%s_deq_count_%d", id.c_str(), t); 83 | expr constr_expr = net_ctx.bool_val(true); 84 | if (t == 0) 85 | constr_expr = in_queue->deq_cnt(t) == 0; 86 | else 87 | constr_expr = 88 | in_queue->deq_cnt(t) == ite(net_ctx.pkt2val(in_queue->elem(0)[t]), 89 | net_ctx.int_val(1), net_ctx.int_val(0)); 90 | constr_map.insert(named_constr(constr_name, constr_expr)); 91 | } 92 | 93 | for (unsigned int t = 0; t < total_time; t++) { 94 | for (unsigned int i = 0; i < out_queue->max_enq(); i++) { 95 | string constr_name = 96 | format_string("%s_output_from_%d_%d", id.c_str(), t, i); 97 | expr constr_expr = 98 | out_queue->enqs(i)[t] == 99 | ((t > 0 && i == 0) ? in_queue->elem(i)[t] : net_ctx.null_pkt()); 100 | constr_map.insert(named_constr(constr_name, constr_expr)); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tests/simple_cp.hpp: -------------------------------------------------------------------------------- 1 | #include "cdeq.hpp" 2 | #include "cenq.hpp" 3 | #include "aipg.hpp" 4 | #include "contention_point.hpp" 5 | 6 | class SimpleCP : public ContentionPoint { 7 | public: 8 | SimpleCP(unsigned int total_time); 9 | Queue *get_in_queue(); 10 | Queue *get_out_queue(); 11 | 12 | private: 13 | vector cenq; 14 | vector cdeq; 15 | vector aipg; 16 | 17 | void add_nodes(); 18 | void add_edges(); 19 | void add_metrics(); 20 | 21 | string cp_model_str(model &m, NetContext &net_ctx, unsigned int t); 22 | }; 23 | 24 | class SimpleQM : public QueuingModule { 25 | public: 26 | SimpleQM(cid_t id, unsigned int total_time, QueueInfo queue_info, NetContext &net_ctx); 27 | 28 | void add_constrs(NetContext &net_ctx, map &constr_map); 29 | private: 30 | void add_proc_vars(NetContext &net_ctx); 31 | }; 32 | -------------------------------------------------------------------------------- /tests/tbf_test.cpp: -------------------------------------------------------------------------------- 1 | #include "tbf_test.hpp" 2 | #include "iostream" 3 | #include "search.hpp" 4 | #include "tbf.hpp" 5 | 6 | /* r : link rate, T: total time 7 | * WL: cenq(t) >= r * t 8 | * QR: cdeq(T) > r * T 9 | * 10 | * We want to ensure that the average dequeue count is at most r 11 | */ 12 | bool test_deq_avg() { 13 | 14 | unsigned int link_rate = 4; 15 | unsigned int total_time = 10; 16 | unsigned int last_t = total_time - 1; 17 | 18 | TBFInfo info; 19 | info.link_rate = link_rate; 20 | info.max_tokens = 10; 21 | info.max_enq = 10; 22 | 23 | TBF *tbf = new TBF(total_time, info); 24 | 25 | Workload wl(100, 1, total_time); 26 | 27 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, 0), Op(Op::Type::GE), new Time(4)), time_range_t(0, last_t), total_time)); 28 | 29 | tbf->set_base_workload(wl); 30 | 31 | cid_t queue_id = tbf->get_in_queue()->get_id(); 32 | 33 | Query sat_query(query_quant_t::FORALL, time_range_t(last_t, last_t), queue_id, 34 | metric_t::CDEQ, Op(Op::Type::EQ), last_t * link_rate); 35 | 36 | tbf->set_query(sat_query); 37 | 38 | if (tbf->satisfy_query() != solver_res_t::SAT) 39 | return false; 40 | 41 | Query unsat_query(query_quant_t::FORALL, time_range_t(last_t, last_t), 42 | queue_id, metric_t::CDEQ, Op(Op::Type::GT), last_t * link_rate); 43 | 44 | tbf->set_query(unsat_query); 45 | 46 | return tbf->satisfy_query() == solver_res_t::UNSAT; 47 | } 48 | 49 | /* m: token bucket size, r: link rate, T: total time 50 | * WL: cenq(T) > r * T 51 | * QR: exists t: deq(t) > m 52 | * 53 | * In average we are enqueueing more than the token bucket size, and we want to 54 | * ensure that bursts do not exceed the token bucket size 55 | */ 56 | bool test_max_burst() { 57 | unsigned int link_rate = 3; 58 | unsigned int max_tokens = 5; 59 | unsigned int total_time = 10; 60 | unsigned int last_t = total_time - 1; 61 | 62 | TBFInfo info; 63 | info.link_rate = link_rate; 64 | info.max_tokens = max_tokens; 65 | info.max_enq = 10; 66 | 67 | TBF *tbf = new TBF(total_time, info); 68 | 69 | Workload wl(100, 1, total_time); 70 | 71 | wl.add_spec(TimedSpec(new Comp(new Indiv(metric_t::CENQ, 0), Op(Op::Type::GT), new Constant((unsigned int)total_time * max_tokens)), time_range_t(last_t, last_t), total_time)); 72 | 73 | tbf->set_base_workload(wl); 74 | 75 | cid_t queue_id = tbf->get_in_queue()->get_id(); 76 | 77 | Query sat_query(query_quant_t::EXISTS, time_range_t(0, last_t), queue_id, 78 | metric_t::DEQ, Op(Op::Type::EQ), max_tokens); 79 | tbf->set_query(sat_query); 80 | 81 | if (tbf->satisfy_query() != solver_res_t::SAT) 82 | return false; 83 | 84 | Query unsat_query(query_quant_t::EXISTS, time_range_t(0, last_t), queue_id, 85 | metric_t::DEQ, Op(Op::Type::GT), max_tokens); 86 | tbf->set_query(unsat_query); 87 | 88 | return tbf->satisfy_query() == solver_res_t::UNSAT; 89 | } 90 | 91 | void TBFTest::add_to_runner(TestRunner *runner) { 92 | runner->add_test_case("tbf_deq_avg", test_deq_avg); 93 | runner->add_test_case("tbf_max_burst", test_max_burst); 94 | } 95 | -------------------------------------------------------------------------------- /tests/tbf_test.hpp: -------------------------------------------------------------------------------- 1 | #include "test_class.hpp" 2 | class TBFTest : TestClass { 3 | public: 4 | void add_to_runner(TestRunner *runner) override; 5 | }; 6 | -------------------------------------------------------------------------------- /tests/test_class.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEST_CLASS_HPP 2 | #define TEST_CLASS_HPP 3 | 4 | #include "test_runner.hpp" 5 | 6 | class TestClass { 7 | public: 8 | virtual void add_to_runner(TestRunner * runner) = 0; 9 | }; 10 | 11 | #endif -------------------------------------------------------------------------------- /tests/test_runner.cpp: -------------------------------------------------------------------------------- 1 | #include "test_runner.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define DASHES "---------------" 8 | 9 | TestRunner::TestRunner() { 10 | test_cases = map(); 11 | results = map(); 12 | } 13 | 14 | bool test_name_match(vector test_names, string name) { 15 | if (test_names.empty()) 16 | return true; 17 | else 18 | return find(test_names.begin(), test_names.end(), name) != test_names.end(); 19 | } 20 | 21 | bool TestRunner::run(vector test_names) { 22 | bool overall_result = true; 23 | for (auto entry : test_cases) { 24 | if (test_name_match(test_names, entry.first)) { 25 | cout << "Running: " << entry.first << endl; 26 | bool result = entry.second(); 27 | results.insert(pair(entry.first, result)); 28 | overall_result &= result; 29 | } 30 | } 31 | return overall_result; 32 | } 33 | 34 | void TestRunner::add_test_case(string name, test_case_t *test_case) { 35 | if (test_cases.find(name) != test_cases.end()) 36 | throw runtime_error("Test case with the same name already exists:" + name); 37 | test_cases.insert(pair(name, test_case)); 38 | } 39 | 40 | string TestRunner::get_report() { 41 | stringstream ss; 42 | ss << endl << DASHES << " Test Results " << DASHES << endl << endl; 43 | for (auto entry : results) 44 | ss << entry.first << ": " << (entry.second ? "Pass" : "Fail") << endl; 45 | ss << endl << DASHES << DASHES << DASHES << endl; 46 | return ss.str(); 47 | } -------------------------------------------------------------------------------- /tests/test_runner.hpp: -------------------------------------------------------------------------------- 1 | #ifndef test_runner_hpp 2 | #define test_runner_hpp 3 | 4 | #include "map" 5 | #include "string" 6 | #include "vector" 7 | 8 | using namespace std; 9 | 10 | typedef bool test_case_t(); 11 | 12 | class TestRunner { 13 | public: 14 | TestRunner(); 15 | 16 | void add_test_case(string name,test_case_t *test_case); 17 | 18 | bool run(vector test_names); 19 | 20 | string get_report(); 21 | 22 | private: 23 | map test_cases; 24 | map results; 25 | }; 26 | 27 | #endif --------------------------------------------------------------------------------