1/*
2 * Copyright (c) 2017 Jason Lowe-Power
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are
7* met: redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer;
9* redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution;
12* neither the name of the copyright holders nor the names of its
13* contributors may be used to endorse or promote products derived from
14* this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*
28* Authors: Jason Lowe-Power
29*/
30
31#include <iostream>
32#include <thread>
33
34using namespace std;
35
36/*
37 * c = a + b
38 */
39void array_add(int *a, int *b, int *c, int tid, int threads, int num_values)
40{
41    for (int i = tid; i < num_values; i += threads) {
42        c[i] = a[i] + b[i];
43    }
44}
45
46
47int main(int argc, char *argv[])
48{
49    unsigned num_values;
50    if (argc == 1) {
51        num_values = 100;
52    } else if (argc == 2) {
53        num_values = atoi(argv[1]);
54        if (num_values <= 0) {
55            cerr << "Usage: " << argv[0] << " [num_values]" << endl;
56            return 1;
57        }
58    } else {
59        cerr << "Usage: " << argv[0] << " [num_values]" << endl;
60        return 1;
61    }
62
63    unsigned cpus = thread::hardware_concurrency();
64
65    cout << "Running on " << cpus << " cores. ";
66    cout << "with " << num_values << " values" << endl;
67
68    int *a, *b, *c;
69    a = new int[num_values];
70    b = new int[num_values];
71    c = new int[num_values];
72
73    if (!(a && b && c)) {
74        cerr << "Allocation error!" << endl;
75        return 2;
76    }
77
78    for (int i = 0; i < num_values; i++) {
79        a[i] = i;
80        b[i] = num_values - i;
81        c[i] = 0;
82    }
83
84    thread **threads = new thread*[cpus];
85
86    // NOTE: -1 is required for this to work in SE mode.
87    for (int i = 0; i < cpus - 1; i++) {
88        threads[i] = new thread(array_add, a, b, c, i, cpus, num_values);
89    }
90    // Execute the last thread with this thread context to appease SE mode
91    array_add(a, b, c, cpus - 1, cpus, num_values);
92
93    cout << "Waiting for other threads to complete" << endl;
94
95    for (int i = 0; i < cpus - 1; i++) {
96        threads[i]->join();
97    }
98
99    delete[] threads;
100
101    cout << "Validating..." << flush;
102
103    int num_valid = 0;
104    for (int i = 0; i < num_values; i++) {
105        if (c[i] == num_values) {
106            num_valid++;
107        } else {
108            cerr << "c[" << i << "] is wrong.";
109            cerr << " Expected " << num_values;
110            cerr << " Got " << c[i] << "." << endl;
111        }
112    }
113
114    if (num_valid == num_values) {
115        cout << "Success!" << endl;
116        return 0;
117    } else {
118        return 2;
119    }
120}
121