    #include <iostream>
    #include <cstring>
    #include <chrono>
    
    // 8Kb of space.
    char smallSpace[8 * 1024];

    // 64Mb of space (larger than cache)
    char bigSpace[64 * 1024 * 1024];

    void populateSpaces(char val)
    {
        memset(smallSpace, val, sizeof(smallSpace));
        memset(bigSpace, val, sizeof(bigSpace));
        std::cout << "Populated spaces" << std::endl;
    }
    
    unsigned int doWork(char* ptr, size_t size)
    {
    	unsigned int total = 0;
    	const char* end = ptr + size;
    	while (ptr < end) {
    		total += *(ptr++);
    	}
    	return total;
    }
    
    unsigned int strideWork(char* ptr, size_t size)
    {
    	unsigned int total = 0;
    	const char* end = ptr + size;
    	const size_t StrideRate = 1024;
    	for (size_t i = 0; i < StrideRate; ++i, ++ptr) {
    		while (ptr < end) {
    			total += (*ptr++);
    		}
    	}
    	return total;
    }

	using namespace std;
	using namespace chrono;

	void doTiming(unsigned int (*function)(char*, size_t), const char* label, char* ptr, size_t size)
	{
		cout << label << ": ";
		const high_resolution_clock::time_point start = high_resolution_clock::now();
		auto result = function(ptr, size);
		const high_resolution_clock::time_point stop = high_resolution_clock::now();
		auto delta = duration_cast<nanoseconds>(stop - start).count();
		cout << "took " << delta << "ns (result is " << result << ")" << endl;
	}
	
    int main()
    {
		cout << "Timer resultion is " << 
			duration_cast<nanoseconds>(high_resolution_clock::duration(1)).count()
			<< "ns" << endl;

		populateSpaces(1);

		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));
		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));
		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));
		doTiming(doWork, "doWork/big", bigSpace, sizeof(bigSpace));
		doTiming(doWork, "doWork/big", bigSpace, sizeof(bigSpace));
		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));
		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));
		doTiming(doWork, "doWork/small", smallSpace, sizeof(smallSpace));

		populateSpaces(2);		

		doTiming(strideWork, "strideWork/small", smallSpace, sizeof(smallSpace));
		doTiming(strideWork, "strideWork/small", smallSpace, sizeof(smallSpace));
		doTiming(strideWork, "strideWork/small", smallSpace, sizeof(smallSpace));
		doTiming(strideWork, "strideWork/big", bigSpace, sizeof(bigSpace));
		doTiming(strideWork, "strideWork/big", bigSpace, sizeof(bigSpace));
    }