source: benchmark/readyQ/locality.cfa @ 3f8baf4

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 3f8baf4 was 3f8baf4, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Fixed the padding

  • Property mode set to 100644
File size: 6.3 KB
Line 
1#include "rq_bench.hfa"
2
3struct Result {
4        uint64_t count;
5        uint64_t dmigs;
6        uint64_t gmigs;
7};
8
9// ==================================================
10thread MyThread {
11        struct MyData * volatile data;
12
13        struct {
14                struct MySpot ** ptr;
15                size_t len;
16        } spots;
17
18        bench_sem sem;
19
20        Result result;
21
22        bool share;
23        size_t cnt;
24        processor * ttid;
25        size_t id;
26};
27
28uint64_t moved(MyThread & this, processor * ttid) {
29        if(this.ttid == ttid) {
30                return 0;
31        }
32        this.ttid = ttid;
33        return 1;
34}
35
36// ==================================================
37struct MyData {
38        uint64_t _p1[16];  // padding
39        uint64_t * data;
40        size_t len;
41        processor * ttid;
42        size_t id;
43        uint64_t _p2[16];  // padding
44};
45
46void ?{}(MyData & this, size_t id, size_t size) {
47        this.len = size;
48        this.data = alloc(this.len, 128`align);
49        this.ttid = active_processor();
50        this.id = id;
51
52        for(i; this.len) {
53                this.data[i] = 0;
54        }
55}
56
57uint64_t moved(MyData & this, processor * ttid) {
58        if(this.ttid == ttid) {
59                return 0;
60        }
61        this.ttid = ttid;
62        return 1;
63}
64
65void access(MyData & this, size_t idx) {
66        size_t l = this.len;
67        this.data[idx % l] += 1;
68}
69
70// ==================================================
71// Atomic object where a single thread can wait
72// May exchanges data
73struct MySpot {
74        MyThread * volatile ptr;
75        size_t id;
76        uint64_t _p1[16];  // padding
77};
78
79void ?{}(MySpot & this, size_t id) {
80        this.ptr = 0p;
81        this.id  = id;
82}
83
84// Main handshake of the code
85// Single seat, first thread arriving waits
86// Next threads unblocks current one and blocks in its place
87// if share == true, exchange data in the process
88bool put( MySpot & this, MyThread & ctx, MyData * data, bool share) {
89        // Attempt to CAS our context into the seat
90        for() {
91                MyThread * expected = this.ptr;
92                if (expected == 1p) { // Seat is closed, return
93                        return true;
94                }
95
96                if (__atomic_compare_exchange_n(&this.ptr, &expected, &ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
97                        if(expected) {
98                                if(share) {
99                                        expected->data = data;
100                                }
101                                post( expected->sem );
102                        }
103                        break; // We got the seat
104                }
105        }
106
107        // Block once on the seat
108        wait(ctx.sem);
109
110        // Someone woke us up, get the new data
111        return false;
112}
113
114// Shutdown the spot
115// Wake current thread and mark seat as closed
116void release( MySpot & this ) {
117        MyThread * val = __atomic_exchange_n(&this.ptr, 1p, __ATOMIC_SEQ_CST);
118        if (!val) {
119                return;
120        }
121
122        // Someone was there, release them
123        post( val->sem );
124}
125
126// ==================================================
127// Do some work by accessing 'cnt' cells in the array
128void work(MyData & data, size_t cnt, uint64_t & state) {
129        for (cnt) {
130                access(data, __xorshift64(state));
131        }
132}
133
134void main(MyThread & this) {
135        uint64_t state = thread_rand();
136
137        // Wait for start
138        wait(this.sem);
139
140        // Main loop
141        for() {
142                // Touch our current data, write to invalidate remote cache lines
143                work(*this.data, this.cnt, state);
144
145                // Wait on a random spot
146                uint64_t idx = __xorshift64(state) % this.spots.len;
147                bool closed = put(*this.spots.ptr[idx], this, this.data, this.share);
148
149                // Check if the experiment is over
150                if (closed) break;
151                if ( clock_mode && stop) break;
152                if (!clock_mode && this.result.count >= stop_count) break;
153
154                // Check everything is consistent
155                verify(this.data);
156
157                // write down progress and check migrations
158                processor * ttid = active_processor();
159                this.result.count += 1;
160                this.result.gmigs += moved(this, ttid);
161                this.result.dmigs += moved(*this.data, ttid);
162        }
163
164        __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST);
165}
166
167void ?{}( MyThread & this, MyData * data, MySpot ** spots, size_t spot_len, size_t cnt, bool share, size_t id) {
168        this.data = data;
169        this.spots.ptr = spots;
170        this.spots.len = spot_len;
171        (this.sem){};
172        this.result.count = 0;
173        this.result.gmigs = 0;
174        this.result.dmigs = 0;
175        this.share = share;
176        this.cnt = cnt;
177        this.ttid = active_processor();
178        this.id = id;
179}
180
181// ==================================================
182int main(int argc, char * argv[]) {
183        unsigned wsize = 2;
184        unsigned wcnt  = 2;
185        bool share = false;
186        cfa_option opt[] = {
187                BENCH_OPT,
188                { 'w', "worksize", "Size of the array for each threads, in words (64bit)", wsize},
189                { 'c', "workcnt" , "Number of words to touch when working (random pick, cells can be picked more than once)", wcnt },
190                { 's', "share"   , "Pass the work data to the next thread when blocking", share, parse_truefalse }
191        };
192        BENCH_OPT_PARSE("cforall cycle benchmark");
193
194        unsigned long long global_count = 0;
195        unsigned long long global_gmigs = 0;
196        unsigned long long global_dmigs = 0;
197
198        MyData * data_arrays[nthreads];
199        for(i; nthreads) {
200                data_arrays[i] = malloc();
201                (*data_arrays[i]){ i, wsize };
202        }
203
204        MySpot * spots[nthreads - nprocs];
205        for(i; nthreads - nprocs) {
206                spots[i] = malloc();
207                (*spots[i]){ i };
208        }
209
210        Time start, end;
211        {
212                BenchCluster bc = { nprocs };
213                threads_left = nprocs;
214                {
215                        MyThread * threads[nthreads];
216                        for(i; nthreads) {
217                                threads[i] = malloc();
218                                (*threads[i]){
219                                        data_arrays[i],
220                                        spots,
221                                        nthreads - nprocs,
222                                        wcnt,
223                                        share,
224                                        i
225                                };
226                        }
227
228                        bool is_tty = isatty(STDOUT_FILENO);
229                        start = getTimeNsec();
230
231                        for(i; nthreads) {
232                                post( threads[i]->sem );
233                        }
234                        wait(start, is_tty);
235
236                        stop = true;
237                        end = getTimeNsec();
238                        printf("\nDone\n");
239
240                        for(i; nthreads) {
241                                post( threads[i]->sem );
242                                MyThread & thrd = join( *threads[i] );
243                                global_count += thrd.result.count;
244                                global_gmigs += thrd.result.gmigs;
245                                global_dmigs += thrd.result.dmigs;
246                        }
247
248                        for(i; nthreads) {
249                                delete(threads[i]);
250                        }
251                }
252        }
253
254        printf("Duration (ms)          : %'ld\n", (end - start)`dms);
255        printf("Number of processors   : %'d\n", nprocs);
256        printf("Number of threads      : %'d\n", nthreads);
257        printf("Total Operations(ops)  : %'15llu\n", global_count);
258        printf("Work size (64bit words): %'15llu\n", wsize);
259        printf("Total Operations(ops)  : %'15llu\n", global_count);
260        printf("Total G Migrations     : %'15llu\n", global_gmigs);
261        printf("Total D Migrations     : %'15llu\n", global_dmigs);
262        printf("Ops per second         : %'18.2lf\n", ((double)global_count) / (end - start)`ds);
263        printf("ns per ops             : %'18.2lf\n", (end - start)`dns / global_count);
264        printf("Ops per threads        : %'15llu\n", global_count / nthreads);
265        printf("Ops per procs          : %'15llu\n", global_count / nprocs);
266        printf("Ops/sec/procs          : %'18.2lf\n", (((double)global_count) / nprocs) / (end - start)`ds);
267        printf("ns per ops/procs       : %'18.2lf\n", (end - start)`dns / (global_count / nprocs));
268        fflush(stdout);
269}
Note: See TracBrowser for help on using the repository browser.