Tervel  1.0.0
A collection of wait-free containers and algorithms.
testObject.h
Go to the documentation of this file.
1 /*
2 #The MIT License (MIT)
3 #
4 #Copyright (c) 2015 University of Central Florida's Computer Software Engineering
5 #Scalable & Secure Systems (CSE - S3) Lab
6 #
7 #Permission is hereby granted, free of charge, to any person obtaining a copy
8 #of this software and associated documentation files (the "Software"), to deal
9 #in the Software without restriction, including without limitation the rights
10 #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 #copies of the Software, and to permit persons to whom the Software is
12 #furnished to do so, subject to the following conditions:
13 #
14 #The above copyright notice and this permission notice shall be included in
15 #all copies or substantial portions of the Software.
16 #
17 #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 #THE SOFTWARE.
24 #
25 */
26 
27 #include <climits>
28 #include <assert.h>
29 #include <atomic>
30 #include <random>
31 #include <string>
32 #include <cstdint>
33 #include <stdio.h>
34 #include <iostream>
35 #include <gflags/gflags.h>
36 
39 
42 // Constructor Arguments
43 DEFINE_int32(capacity, 64, "The initial capacity of the hash map");
44 
45 // Operation Rates
46 DEFINE_int32(cas_rate, 20,
47  "The chance (0-100) of the CAS operation being called.");
48 DEFINE_int32(at_rate, 20,
49  "The chance (0-100) of the at operation being called.");
50 DEFINE_int32(pushBack_rate, 20,
51  "The chance (0-100) of pushBack operation being called.");
52 DEFINE_int32(popBack_rate, 20,
53  "The chance (0-100) of popBack operation being called.");
54 DEFINE_int32(size_rate, 20,
55  "The chance (0-100) of size operation being called.");
56 
58 DEFINE_int32(num_threads, 1, "The number of executing threads.");
59 DEFINE_int32(execution_time, 5, "The amount of time to run the tests");
60 
61 typedef uint64_t Value;
62 class TestObject {
63  public:
64  enum op_codes : int { cas = 0, at, popBack, pushBack, size, LENGTH };
65  static const int k_num_functions = op_codes::LENGTH;
66  int* func_call_rate_;
67  std::string* func_name_;
68 
69  std::atomic<int> func_call_count_[k_num_functions];
70  void set_rates() {
71  func_call_rate_ = new int[k_num_functions];
72  func_name_ = new std::string[k_num_functions];
73 
74  #define MACRO_ADD_RATE(TervelOpName) \
75  func_name_[op_codes::TervelOpName] = "" #TervelOpName ; \
76  func_call_rate_[op_codes::TervelOpName] = FLAGS_##TervelOpName##_rate;
77 
83 
84  for (int i = 0; i < k_num_functions; i++) {
85  func_call_count_[i].store(0);
86  }
87  };
88 
90  : num_threads_(FLAGS_num_threads),
91  execution_time_(FLAGS_execution_time),
92  test_class_(new TestClass<Value>( (num_threads_+1), FLAGS_capacity)) {
93  set_rates();
94  };
95 
97  delete test_class_;
98  };
99 
100  // Define these functions if the test object requires per thread actions
101  void attachThread(int threadID) {
103  };
104 
105  void detachThread(int threadID) {
107  };
108 
110  /* This function is useful for enabling a blocking operation to return*/
111  };
112 
113  void init() {
114  /* This function is useful if you need to pre-fill a data structure */
115  }
116  void destroy() {
117  delete test_class_;
118  };
119 
120  void run(int64_t thread_id) {
121  // Initial Setup
122  attachThread(thread_id);
123 
124  int lcount = 0;
125  int func_call_count[k_num_functions];
126  int func_call_rate[k_num_functions];
127  int max_rand = 0;
128  for (int i = 0; i < k_num_functions; i++) {
129  func_call_rate[i] = func_call_rate_[i] + max_rand;
130  max_rand = func_call_rate[i];
131  func_call_count[i] = 0;
132  }
133 
134  // Setup Random Number Generation
135  std::default_random_engine generator;
136  std::uniform_int_distribution<int> distribution(0, max_rand);
137  std::uniform_int_distribution<int> largeValue(0, UINT_MAX);
138 
139  // Wait for start signle
140  ready_count_.fetch_add(1);
141  while (wait_flag_.load());
142 
144  while (running_.load()) {
145  lcount++;
146  int op = distribution(generator);
147  if (op <= func_call_rate[op_codes::cas]) {
148  size_t s = test_class_->size();
149  if (s == 0) {
150  continue;
151  }
152  Value temp;
153  int idx = largeValue(generator) % s;
154  if (test_class_->at(idx, temp)) {
155  test_class_->cas(idx, temp, (temp * 2) & (~0x7));
156  func_call_count[op_codes::cas]++;
157  }
158  } else if (op <= func_call_rate[op_codes::at]) {
159  size_t s = test_class_->size();
160  if (s == 0) {
161  continue;
162  }
163 
164  Value temp;
165  size_t idx = largeValue(generator) % s;
166  test_class_->at(idx, temp);
167 
168  func_call_count[op_codes::at]++;
169  } else if (op <= func_call_rate[op_codes::popBack]) {
170  Value temp;
171  if (test_class_->pop_back(temp))
172  func_call_count[op_codes::popBack]++;
173  } else if (op <= func_call_rate[op_codes::pushBack]) {
174  Value temp = largeValue(generator) & (~0x7);
175 
176  test_class_->push_back(temp);
177  func_call_count[op_codes::pushBack]++;
178  } else if (op <= func_call_rate[op_codes::size]) {
179  test_class_->size();
180  func_call_count[op_codes::size]++;
181  } else {
182  assert(false);
183  }
184  }
185  ready_count_.fetch_add(1);
186 
187  add_results(func_call_count);
188  detachThread(thread_id);
189  };
190 
191  std::string toString() {
192  std::string res("");
193  res += "Test Handler Configuration\n";
194  res += "\tThreads:" + std::to_string(num_threads_) + "\n";
195  res += "\tExecution Time: " + std::to_string(execution_time_) + "\n";
196 
197  res += "\tOperation rates\n";
198  for (int i = 0; i < k_num_functions; i++) {
199  res += "\t\t" + func_name_[i] + ": ";
200  res += std::to_string(func_call_rate_[i]) + "\n";
201  }
202 
203  return res;
204  };
205 
206  std::string results() {
207  std::string res("");
208  res += "-- Test Results--\n";
209  res += this->toString() + "\n";
210 
211  res += "Test Class Configuration\n";
212  res += test_class_->toString() + "\n";
213 
214 
215  res += "Operation Counts\n";
216  int sum = 0;
217  for (int i = 0; i < k_num_functions; i++) {
218  res += "\t" + func_name_[i] + ": " +
219  std::to_string(func_call_count_[i].load()) + "\n";
220  sum += func_call_count_[i].load();
221  }
222  res += "Total Operations: " + std::to_string(sum) + "\n";
223  res += "Reported Size: " + std::to_string(test_class_->size()) + "\n";
224  {int temp = func_call_count_[op_codes::pushBack] - func_call_count_[op_codes::popBack];
225  res += "Calculated Size: " + std::to_string(temp) + "\n";}
226  return res;
227  }
228 
229  void add_results(int func_call_count[k_num_functions]) {
230  for (int i = 0; i < k_num_functions; i++) {
231  func_call_count_[i].fetch_add(func_call_count[i]);
232  }
233  }
234 
235  const int num_threads_;
236  const int execution_time_;
237 
239 
240  std::atomic<bool> wait_flag_{true};
241  std::atomic<bool> running_{true};
242  std::atomic<int> ready_count_{0};
243 };
#define MACRO_ADD_RATE(TervelOpName)
std::atomic< bool > wait_flag_
Definition: testObject.h:232
TestClass< Value, Value > * test_class_
Definition: testObject.h:226
std::string results()
Definition: testObject.h:206
void destroy()
Definition: testObject.h:116
void detach_thread()
Definition: blank_api.h:43
TestObject()
Definition: testObject.h:89
void attachThread(int threadID)
Definition: testObject.h:101
std::atomic< bool > running_
Definition: testObject.h:229
void run(int64_t thread_id)
Definition: testObject.h:120
bool pop_back(T &value)
Definition: wf_vector_api.h:71
Definition: testObject.h:60
std::string * func_name_
Definition: testObject.h:65
Definition: testObject.h:64
Definition: testObject.h:64
void detachThread(int threadID)
Definition: testObject.h:105
std::atomic< int > func_call_count_[k_num_functions]
Definition: testObject.h:67
DEFINE_int32(capacity, 64,"The initial capacity of the hash map")
Change this when including a new data structure.
bool cas(size_t idx, T &expValue, T newValue)
Definition: wf_vector_api.h:62
std::atomic< int > ready_count_
Definition: testObject.h:230
void attach_thread()
Definition: blank_api.h:40
size_t push_back(T value)
Definition: wf_vector_api.h:66
const int num_threads_
Definition: testObject.h:223
void add_results(int func_call_count[k_num_functions])
Definition: testObject.h:217
int * func_call_rate_
Definition: testObject.h:64
Definition: testObject.h:64
op_codes
Definition: testObject.h:62
uint64_t Value
Definition: testObject.h:59
Definition: testObject.h:64
const int execution_time_
Definition: testObject.h:224
Definition: testObject.h:62
void init()
Definition: testObject.h:113
size_t size()
Definition: blank_api.h:57
std::string toString()
Definition: testObject.h:191
bool at(size_t idx, T &value)
Definition: wf_vector_api.h:58
static const int k_num_functions
Definition: testObject.h:63
Definition: blank_api.h:31
void set_rates()
Definition: testObject.h:70
Definition: testObject.h:64
~TestObject()
Definition: testObject.h:96
void extra_end_signal()
Definition: testObject.h:109
std::string toString()
Definition: blank_api.h:36