// Lab 1: Histogram generation // Compile as // c++ -std=c++11 -O2 -pthread histogram.cxx ee155_utils.cxx histogram_user.cxx #include #include #include #include using namespace std; #include "ee155_utils.hxx" // How many buckets the histogram has. extern const int N_BUCKETS=5; static void compute_1thread (vector &hist, const vector &input_data); static void multithreaded (const vector &input_data, const vector &ref_hist, int n_threads); static void sanity_check_hist (const vector &histogram,int n_input_vals); vector compute_multithread (const vector &input_data, int n_threads); //////////////////////////////////////////////////////////////////////////////// // Program main //////////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { if(argc != 2) DIE ("Usage: histogram "); //int n_input_vals = std::stoi(argv[1]); int n_input_vals = strtol(argv[1], NULL, 10); vector ref_hist, input_data (n_input_vals); LOG("Building histograms with " << n_input_vals << " entries"); LOG ("There are " < dist(0,N_BUCKETS-1); for(int i=0; i times; for (int loop=0; loop<4; ++loop) { LOG ("\nCreating the golden histogram."); auto start = start_time(); compute_1thread (ref_hist, input_data); double time = delta_usec(start)/1000.0; LOG ("Single-threaded creation took " << time << "msec"); sanity_check_hist(ref_hist, n_input_vals); times.push_back (time); } analyze_times ("Golden", times, "msec"); multithreaded (input_data, ref_hist, 1); // Multithreaded (just 1 thread) multithreaded (input_data, ref_hist, 2); // 2 threads multithreaded (input_data, ref_hist, 4); // 4 threads multithreaded (input_data, ref_hist, 8); // 8 threads multithreaded (input_data, ref_hist, 16); multithreaded (input_data, ref_hist, 32); multithreaded (input_data, ref_hist, 64); multithreaded (input_data, ref_hist, 128); } // This function computes the reference solution without any threading. static void compute_1thread (vector &hist, const vector &input_data) { // Initialize histogram hist = vector (N_BUCKETS, 0); // Bin the elements in the input stream for (int input_val : input_data) ++hist[input_val]; } //************************************************************************ // Now for the multithreaded solution. This function is just a wrapper around // compute_multithread(), which everyone writes themself. This wrapper takes // care of timing and sanity checking. //************************************************************************ static void multithreaded (const vector &input_data, const vector &ref_hist, int n_threads) { int n_input_vals = input_data.size(); vector times; for (int loop=0; loop<5; ++loop) { //LOG(endl<<"Creating histogram using "< user_hist=compute_multithread (input_data, n_threads); double time = delta_usec (start)/1000.0; times.push_back (time); //LOG (n_threads << " threads took " << time << "ms"); sanity_check_hist(user_hist, n_input_vals); // Check the multithreaded results vs. the reference. float diff = 0.0; for(int i = 0; i < N_BUCKETS; i++) diff += abs(ref_hist[i] - user_hist[i]); if (diff > 0) DIE (diff << " errors between the reference and user results."); } analyze_times (to_string(n_threads)+" threads", times, "msec"); } // This function sanity-checks that the histogram contains a total of // 'n_input_vals' elements. It does so by summing the number in each bucket. static void sanity_check_hist (const vector &histogram,int n_input_vals){ int sum = 0; for(int bucket : histogram) sum += bucket; if (sum != n_input_vals) DIE ("Histogram error: expected "<