Reputation: 9
I have written a C++ program to benchmark various sorting algorithms to find out which one is the fastest. However, I am facing some issues while executing my code.
I first created a class to time the algorithms using a constructor and a destructor. I then used std::chrono::time_point_cast
to explicitly cast the time to milliseconds. However, the program ended up showing zero milliseconds have elapsed every time I run my program.
Please do note that I have included the chrono header file.
Here's the part of the involved program source code.
Class definition
int Array[20], size = 20;
class BenchmarkTimer
{
public:
std::chrono::time_point<std::chrono::high_resolution_clock> startpt;
float ms;
long long duration;
BenchmarkTimer() : ms(0), duration(0)
{
startpt = std::chrono::high_resolution_clock::now();
}
~BenchmarkTimer()
{
auto endpt = std::chrono::high_resolution_clock::now();
auto init = std::chrono::time_point_cast<std::chrono::milliseconds>(startpt).time_since_epoch().count();
auto final = std::chrono::time_point_cast<std::chrono::milliseconds>(endpt).time_since_epoch().count();
auto duration = final - init;
}
};
Selection Sort function (This is just one of many sorting algorithms).
void SelectionSort(int Array[])
{
BenchmarkTimer timer;
int temp, smallest, position, j;
for (int i = 0; i < size - 1; i++)
{
smallest = Array[i];
position = i;
for (j = i + 1; j < size; j++)
if (Array[j] < smallest)
{
smallest = Array[j];
position = j;
}
temp = Array[i];
Array[i] = Array[position];
Array[position] = temp;
}
DisplayArray(Array);
std::cout << "\nTime taken to sort the array: " << timer.duration << " ms" << std::endl;
}
The DisplayArray(Array)
function call simply displays the array on to the screen.
I want the program to display the number of milliseconds elapsed.
Right now, the actual output is:
Time taken to sort the array: 0 ms
But I want the output to be:
Time taken to sort the array: 13 ms
(13 ms is just an example.)
I would suggest you to suggest simpler solutions, as I am in the intermediate level of C++ programming.
Thanks in advance!
Upvotes: 0
Views: 100
Reputation: 219345
One very simple way to address this is to just put the print statement for the timer in ~BenchmarkTimer()
. The BenchmarkTimer
constructor could take a message to augment the output in ~BenchmarkTimer()
. This might look like:
class BenchmarkTimer
{
public:
std::string msg_;
std::chrono::steady_clock::time_point startpt_;
explicit BenchmarkTimer(std::string msg)
: msg_(std::move(msg))
, startpt_(std::chrono::steady_clock::now())
{
}
~BenchmarkTimer()
{
using namespace std::chrono;
auto endpt = steady_clock::now();
std::cout << msg_ << duration_cast<milliseconds>(endpt - startpt_).count() << " ms\n";
}
BenchmarkTimer(BenchmarkTimer const&) = delete;
BenchmarkTimer& operator=(BenchmarkTimer const&) = delete;
};
You would use it by constructing a BenchmarkTimer
at the point where you want to start timing, with an appropriate message, and it will record and log the time for the scope of the timer. For example:
void SelectionSort(int Array[])
{
BenchmarkTimer timer{"\nTime taken to sort the array: "};
int temp, smallest, position, j;
// ...
DisplayArray(Array);
} // Output: Time taken to sort the array: 13 ms
Upvotes: 1
Reputation: 180998
Your issue here is that you only do you time calculation in BenchmarkTimer
's destructor. This means duration
will always be 0 since it only changes in the destructor and you can't access the object after it gets destructed.
There are a few ways to fix this. The first is to just move the timing code into the function. Secondly you could modify BenchmarkTimer
to take a function object in the constructor that will be the code to run and then do your calculations in the constructor. That would look like
class BenchmarkTimer
{
public:
std::chrono::time_point<std::chrono::high_resolution_clock> startpt;
float ms;
long long duration;
template<typename Func>
BenchmarkTimer(Func func) : ms(0), duration(0)
{
startpt = std::chrono::high_resolution_clock::now();
func();
auto endpt = std::chrono::high_resolution_clock::now();
auto diff = end-start;
duration = diff.count();
}
};
void SelectionSort(int Array[])
{
BenchmarkTimer timer([&]()
{
int temp, smallest, position, j;
for (int i = 0; i < size - 1; i++)
{
smallest = Array[i];
position = i;
for (j = i + 1; j < size; j++)
if (Array[j] < smallest)
{
smallest = Array[j];
position = j;
}
temp = Array[i];
Array[i] = Array[position];
Array[position] = temp;
}
});
DisplayArray(Array);
std::cout << "\nTime taken to sort the array: " << timer.duration << " ms" << std::endl;
}
Another option would be to add another function to BenchmarkTimer
that you call once you want it to do the calculations, and move your destructor code into there. Take care with that as in your destructor you declare a duration
variable that hides the class's duration
. The code should be something like
auto endpt = std::chrono::high_resolution_clock::now();
auto init = std::chrono::time_point_cast<std::chrono::milliseconds>(startpt).time_since_epoch().count();
auto final = std::chrono::time_point_cast<std::chrono::milliseconds>(endpt).time_since_epoch().count();
duration = final - init;
// ^ no auto here
Upvotes: 1