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 
37 #define __tervel_xstr(s) __tervel_str(s)
38 #define __tervel_str(s) #s
39 #include __tervel_xstr(CONTAINER_FILE)
40 #undef __tervel_str
41 #undef __tervel_xstr
42 
45 // Constructor Arguments
46 DEFINE_int32(capacity, 64, "The initial capacity of the container");
47 
48 // Operation Rates
49 
50 DEFINE_int32(prefill, 0, "The number of elements to be initially inserted.");
51 DEFINE_int32(enqueue_rate, 60, "The percent of insert operations.");
52 DEFINE_int32(dequeue_rate, 40, "The percent of find operations.");
53 const int32_t FLAGS_failenqueue_rate = 0;
54 const int32_t FLAGS_faildequeue_rate = 0;
55 
57 DEFINE_int32(num_threads, 1, "The number of executing threads.");
58 DEFINE_int32(execution_time, 5, "The amount of time to run the tests");
59 
60 
61 
62 typedef int64_t Value;
63 class TestObject {
64  public:
66  static const int k_num_functions = op_codes::LENGTH;
67 
68  int* func_call_rate_;
69  std::string* func_name_;
70 
71  std::atomic<int> func_call_count_[k_num_functions];
72  void set_rates() {
73  func_call_rate_ = new int[k_num_functions];
74  func_name_ = new std::string[k_num_functions];
75  #define MACRO_ADD_RATE(TervelOpName) \
76  func_name_[op_codes::TervelOpName] = "" #TervelOpName ; \
77  func_call_rate_[op_codes::TervelOpName] = FLAGS_##TervelOpName##_rate; \
78  func_call_count_[op_codes::TervelOpName].store(0);
79 
84  };
85 
87  : num_threads_(FLAGS_num_threads)
88  , execution_time_(FLAGS_execution_time) {
89  set_rates();
90 
91  test_class_ = new TestClass<Value>(FLAGS_num_threads+1, FLAGS_capacity);
92 
93 
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 sanity_check();
114 
115  void init() {
116  /* This function is useful if you need to pre-fill a data structure */
117  sanity_check();
118 
119  std::default_random_engine generator;
120  std::uniform_int_distribution<uint64_t> largeValue(0, UINT_MAX);
121  for (int i = 0; i < FLAGS_prefill; i++) {
122  uint64_t x = largeValue(generator) & (~0x3);
123  test_class_->enqueue(x);
124  }
125  }
126  void destroy() {
127  delete test_class_;
128  };
129 
130  void run(int64_t thread_id) {
131  // Initial Setup
132  attachThread(thread_id);
133 
134  int lcount = 0;
135  int ecount = 0;
136  int func_call_count[k_num_functions];
137  int func_call_rate[k_num_functions];
138  int max_rand = 0;
139  for (int i = 0; i < k_num_functions; i++) {
140  func_call_rate[i] = func_call_rate_[i] + max_rand;
141  max_rand = func_call_rate[i];
142  func_call_count[i] = 0;
143  }
144 
145  // Setup Random Number Generation
146  std::default_random_engine generator;
147  std::uniform_int_distribution<int> distribution(0, max_rand);
148  std::uniform_int_distribution<int> largeValue(0, UINT_MAX);
149 
150  // Wait for start signal
151  ready_count_.fetch_add(1);
152  while (wait_flag_.load());
153 
155  while (running_.load()) {
156  lcount++;
157  int op = distribution(generator);
158 
159  if (op <= func_call_rate[op_codes::enqueue]) {
160  // Value x = largeValue(generator) & (~0x3);
161  Value x = (thread_id << 56) | ecount;
162  if (test_class_->enqueue(x)) {
163  func_call_count[op_codes::enqueue]++;
164  ecount++;
165  } else {
166  func_call_count[op_codes::failenqueue]++;
167  }
168  } else if (op <= func_call_rate[op_codes::dequeue]) {
169  Value x;
170  if (test_class_->dequeue(x)) {
171  func_call_count[op_codes::dequeue]++;
172  } else {
173  func_call_count[op_codes::faildequeue]++;
174  }
175  } else {
176  assert(false);
177  }
178  }
179  ready_count_.fetch_add(1);
180 
181  add_results(func_call_count);
182  detachThread(thread_id);
183  };
184 
185  std::string toString() {
186  std::string res("");
187  res += "Test Handler Configuration\n";
188  res += "\tThreads:" + std::to_string(num_threads_) + "\n";
189  res += "\tExecution Time: " + std::to_string(execution_time_) + "\n";
190 
191  res += "\tOperation rates\n";
192  for (int i = 0; i < k_num_functions; i++) {
193  res += "\t\t" + func_name_[i] + ": ";
194  res += std::to_string(func_call_rate_[i]) + "\n";
195  }
196 
197  return res;
198  };
199 
200  std::string results() {
201  std::string res("");
202  res += "-- Test Results--\n";
203  res += this->toString() + "\n";
204 
205  res += "Test Class Configuration\n";
206  res += test_class_->toString() + "\n";
207 
208 
209  res += "Operation Counts\n";
210  int sum = 0;
211  for (int i = 0; i < k_num_functions; i++) {
212  res += "\t" + func_name_[i] + ": " +
213  std::to_string(func_call_count_[i].load()) + "\n";
214  sum += func_call_count_[i].load();
215  }
216  res += "Total Operations: " + std::to_string(sum) + "\n";
217  return res;
218  }
219 
220  void add_results(int func_call_count[k_num_functions]) {
221  for (int i = 0; i < k_num_functions; i++) {
222  func_call_count_[i].fetch_add(func_call_count[i]);
223  }
224  }
225 
226  const int num_threads_;
227  const int execution_time_;
228 
230 
231  std::atomic<bool> wait_flag_{true};
232  std::atomic<bool> running_{true};
233  std::atomic<int> ready_count_{0};
234 };
235 
236 
237 void TestObject::
239  bool res;
240  Value i, j, temp;
241 
242  for (i = 0; i < FLAGS_capacity; i++) {
243  bool res = test_class_->enqueue(i);
244  assert(res && "If this assert fails then the there is an issue with either pushing or determining that it is full");
245  };
246 
247  res = test_class_->enqueue(0xDEADBEEF);
248  assert(!res && "If this assert fails then the there is an issue with either pushing or determining that it is full");
249 
250  for (j = 0; j < FLAGS_capacity; j++) {
251  res = test_class_->dequeue(temp);
252  assert(res && "If this assert fails then the there is an issue with either poping or determining that it is not empty");
253  assert(temp==j && "If this assert fails then there is an issue with determining the top element");
254  };
255 
256  res = test_class_->dequeue(temp);
257  assert(!res && "If this assert fails then there is an issue with pop or determining that it is empty");
258 };
std::atomic< bool > wait_flag_
Definition: testObject.h:232
TestClass< Value, Value > * test_class_
Definition: testObject.h:226
std::string results()
Definition: testObject.h:200
void destroy()
Definition: testObject.h:126
void detach_thread()
Definition: blank_api.h:43
TestObject()
Definition: testObject.h:86
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:130
Definition: testObject.h:60
void sanity_check()
Definition: testObject.h:238
std::string * func_name_
Definition: testObject.h:65
void detachThread(int threadID)
Definition: testObject.h:105
std::atomic< int > func_call_count_[k_num_functions]
Definition: testObject.h:67
const int32_t FLAGS_failenqueue_rate
Definition: testObject.h:53
DEFINE_int32(capacity, 64,"The initial capacity of the hash map")
Change this when including a new data structure.
const int32_t FLAGS_faildequeue_rate
Definition: testObject.h:54
bool dequeue(T &val)
Definition: linux_API.h:20
#define MACRO_ADD_RATE(TervelOpName)
Definition: testObject.h:65
std::atomic< int > ready_count_
Definition: testObject.h:230
void attach_thread()
Definition: blank_api.h:40
const int num_threads_
Definition: testObject.h:223
TestClass< Value > * test_class_
Definition: testObject.h:229
void add_results(int func_call_count[k_num_functions])
Definition: testObject.h:217
int * func_call_rate_
Definition: testObject.h:64
op_codes
Definition: testObject.h:62
uint64_t Value
Definition: testObject.h:59
Definition: testObject.h:65
const int execution_time_
Definition: testObject.h:224
Definition: testObject.h:65
Definition: testObject.h:62
void init()
Definition: testObject.h:115
std::string toString()
Definition: testObject.h:185
static const int k_num_functions
Definition: testObject.h:63
Definition: testObject.h:65
bool enqueue(T value)
Definition: linux_API.h:15
void set_rates()
Definition: testObject.h:72
~TestObject()
Definition: testObject.h:96
void extra_end_signal()
Definition: testObject.h:109
std::string toString()
Definition: blank_api.h:36