-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathspmv.c
163 lines (139 loc) · 3.69 KB
/
spmv.c
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
#include "random.h"
#include "parallel_ligra.h"
static int phase = 0;
static int global_phase = 0;
uint32_t* value_in;
uint32_t* value_out;
static inline void spmv_algo(int id, struct thread_buffer *b, struct node *n);
static inline void spmv_algo_push(int id, struct thread_buffer *b, struct node *n);
pthread_t threads[ALGO_NB_THREADS];
int CAS(uint32_t * ptr, uint32_t oldV, uint32_t newV){
return(__sync_bool_compare_and_swap((uint32_t*)ptr, *((uint32_t*)&oldV), *((uint32_t*)&newV)));
}
void write_add(uint32_t* _rank, uint32_t val){
volatile uint32_t newV, oldV;
do {oldV = *_rank; newV = oldV+val;}
while(!CAS(_rank, oldV, newV));
}
static inline used void *parallells(void *data) {
int id = (long)data;
__id = id + NB_CONCURRENCY;
if(id != 0) {
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(id, &mask);
sched_setaffinity(gettid(), sizeof(mask), &mask);
}
begin:;
if(!has_work_to_do())
usleep(10000);
__sync_fetch_and_add(&waiting, 1);
while(*(volatile int*)¶llels_done == 0) NOP10();
__sync_fetch_and_add(&waiting, -1);
struct thread_buffer b;
struct node *n;
init_thread_buffer(&b);
do {
struct work w = get_work(id);
foreach_task(w, ids, n) {
if(mode == PUSH)
spmv_algo_push(id, &b, n);
else
spmv_algo(id, &b, n);
}
} while(sub_has_more_work());
thread_flush(&b);
__sync_fetch_and_add(¶llels_done, -1);
while(*(volatile int*)¶llels_done != 0) NOP10();
if(id != 0)
goto begin;
return NULL;
}
void spmv_construct(void) {
if(load_mode !=8)
for(size_t i = 1; i < ALGO_NB_THREADS; i++)
pthread_create(&threads[i], NULL, parallells, (void*)i);
}
void spmv_destruct(void) {
if(load_mode != 8)
for(size_t i = 1; i < ALGO_NB_THREADS; i++)
pthread_cancel(threads[i]);
}
static used void iterator(struct node *nodes, algo_fun_t algo) {
int iterations = 0;
{
do { // iterations
start_iteration();
while(*(volatile int*)&waiting != ALGO_NB_THREADS - 1) NOP10(); // wait for all threads
parallels_done = ALGO_NB_THREADS; // go!
parallells((void*)0);
stop_iteration();
iterations++;
phase = 1 - phase;
global_phase = iterations;
} while(has_work_to_do());
}
}
void spmv_reset(struct node *nodes) {
}
uint32_t edges_seen = 0;
/*
* Actual spmv algorithm
*/
static inline void spmv_algo(int id_, struct thread_buffer *b, struct node *n) {
struct node *dst;
struct edge *e;
if(global_phase>1) return;
uint32_t n_id = id(n);
foreach_incoming_edges(n,dst,e){
value_out[n_id] += 0.001 * value_in[id(dst)];
}
}
/*
* Actual spmv algorithm
*/
static inline void spmv_algo_push(int id_, struct thread_buffer *b, struct node *n) {
struct node *dst;
struct edge *e;
if(global_phase>1) return;
uint32_t n_id = id(n);
foreach_outgoing_edges(n,dst,e){
write_add(&value_out[n_id], 0.001 * value_in[id(dst)]);
}
}
/*
* Default function that launches a spmv
*/
void spmv(struct node *nodes) {
value_out = (uint32_t*) malloc(NB_NODES * sizeof(uint32_t));
value_in = (uint32_t*) malloc(NB_NODES * sizeof(uint32_t));
parallel_for(uint32_t i = 0; i < NB_NODES ; i++){
value_out[i] = 0.0;
value_in[i] = i;
}
if(load_mode == 8) {
parallel_for(uint32_t i = 0; i < nb_edges; i++) {
struct edge_t* e = &memblock[i];
write_add(&value_out[e->src], value_in[e->dst]);
}
}
else {
if(!get_task_list())
init_task_list(NB_NODES);
reset_task_lists();
struct node *n;
struct node_list l = get_all_nodes();
foreach_node(l, n)
add_task(n);
free(l.starting_nodes);
iterator(nodes, spmv_algo) ;
}
}
/* Rerun
*/
void spmv_rerun(struct node *nodes) {
iterator(nodes, spmv_algo );
}
struct algo_func current_algo = {
.reset = spmv_reset, .main = spmv, .construct = spmv_construct, .destruct = spmv_destruct
};