-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindependent_method.cpp
More file actions
170 lines (137 loc) · 5.87 KB
/
Copy pathindependent_method.cpp
File metadata and controls
170 lines (137 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "independent_method.h"
#include <cmath>
using namespace std;
void IndependentMethod::work(int thread_index, const vector<tuple<uint64_t, uint64_t>>& data, int start_index, int bucket_size) {
vector<vector<tuple<uint64_t, uint64_t>>> buffer(get_num_partitions());
barrier->wait();
if (VERBOSE == 2) {
cerr << "Thread #" << thread_index << ": start_index= " << start_index << endl;
}
// Identify the partition by hash function
for (int i = start_index; i < start_index + bucket_size; i++) {
// Hash key to get the partition key
uint64_t key = get<0>(data[i]);
int partition_key = hash_function(key);
// Add tuple to local buffer
buffer[partition_key].push_back(data[i]);
}
buffer_collection[thread_index] = move(buffer);
barrier->wait();
if (VERBOSE == 2) {
cerr << "Thread #" << thread_index << " completed... " << endl;
}
}
double IndependentMethod::thread_work_affinity(const vector<tuple<uint64_t, uint64_t>>& data){
buffer_collection.resize(NUM_THREADS);
uint64_t bucket_size = data.size() / NUM_THREADS;
if (VERBOSE == 2) {
cerr << "Starting with " << NUM_THREADS << " threads and bucket size " << bucket_size << endl;
}
auto set_affinity = read_affinity_file();
vector<thread> threads(NUM_THREADS);
for (int i = 0; i < NUM_THREADS; ++i) {
threads[i] = thread(&IndependentMethod::work, this, i, cref(data), i * bucket_size, bucket_size);
if(!set_affinity){
continue; // skip setting affinity
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(affinity[i], &cpuset);
int rc = pthread_setaffinity_np(threads[i].native_handle(), sizeof(cpu_set_t), &cpuset);
if (VERBOSE == 2) {
cerr << "Thread #" << i << " @ " << affinity[i] << "- start_index: " << i * bucket_size << endl;
}
if (rc != 0) {
cerr << "Error calling pthread_setaffinity_np: " << rc << endl;
}
}
// Join and start threads
// For i threads
for(int i = 0; i < NUM_THREADS; i++) {
//cerr << "before Joining thread #" << i << endl;
threads[i].detach();
//cerr << "after Joining thread #" << i << endl;
}
barrier->wait();
// Start times here
//cerr << "----Before Timer start----" << endl;
auto start_time = chrono::high_resolution_clock::now();
//cerr << "----After Timer start----" << endl;
barrier->wait();
//cerr << "----Before Timer end----" << endl;
// End timer and calculate duration
auto end_time = chrono::high_resolution_clock::now();
int64_t duration = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
//cerr << "----After Timer end----" << endl;
// Return time (convert from microseconds to milliseconds)
return static_cast<double>(duration) / 1000;
}
double IndependentMethod::thread_work(const vector<tuple<uint64_t, uint64_t>>& data) {
buffer_collection.resize(NUM_THREADS);
uint64_t bucket_size = data.size() / NUM_THREADS;
if (VERBOSE == 2) {
cerr << "Starting with " << NUM_THREADS << " threads and bucket size " << bucket_size << endl;
}
vector<thread> threads(NUM_THREADS);
for (int i = 0; i < NUM_THREADS; ++i) {
threads[i] = thread(&IndependentMethod::work, this, i, cref(data), i * bucket_size, bucket_size);
if (VERBOSE == 2) {
cerr << "Thread #" << i << "- start_index: " << i * bucket_size << endl;
}
}
// Join and start threads
// For i threads
for(int i = 0; i < NUM_THREADS; i++) {
//cerr << "before Joining thread #" << i << endl;
threads[i].detach();
//cerr << "after Joining thread #" << i << endl;
}
barrier->wait();
// Start times here
//cerr << "----Before Timer start----" << endl;
auto start_time = chrono::high_resolution_clock::now();
//cerr << "----After Timer start----" << endl;
barrier->wait();
//cerr << "----Before Timer end----" << endl;
// End timer and calculate duration
auto end_time = chrono::high_resolution_clock::now();
int64_t duration = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
//cerr << "----After Timer end----" << endl;
// Return time (convert from microseconds to milliseconds)
return static_cast<double>(duration) / 1000;
}
void IndependentMethod::print_buffers_everything() {
for (int i = 0; i < buffer_collection.size(); i++) {
for (int j = 0; j < buffer_collection[i].size(); j++) {
for (int k = 0; k < buffer_collection[i][j].size(); k++) {
cerr << "Thread: " << i << " Partition: " << j
<< " Key: " << get<0>(buffer_collection[i][j][k])
<< " Value: " << get<1>(buffer_collection[i][j][k]) << endl;
}
}
}
}
void IndependentMethod::print_buffers_partition_entries() {
for (int i = 0; i < buffer_collection.size(); i++) {
for (int j = 0; j < buffer_collection[i].size(); j++) {
int partition_size = buffer_collection[i][j].size();
cerr << "Thread: " << i << " Partition: " << j << "# entries: " << partition_size << endl;
}
}
}
void IndependentMethod::print_buffers_partition_statistics() {
int num_partitions = get_num_partitions();
float mean = (DATA_SIZE / num_partitions) / NUM_THREADS;
float std_dev = 0.0;
for (int i = 0; i < buffer_collection.size(); i++) {
for (int j = 0; j < buffer_collection[i].size(); j++) {
int partition_size = buffer_collection[i][j].size();
float variance = partition_size - mean;
std_dev += variance * variance;
}
}
std_dev = sqrt(std_dev / num_partitions);
if (VERBOSE == 1) {
cerr << "Expected Partition Size: " << mean << " ±" << std_dev << endl;
}
}