Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ Visual Benchmarking using C++ and Chrome Tracing for single threaded projects, m

##### To start the session for benchmarking, call this function
```
START_SESSION("Session Name");
START_BENCHMARK_SESSION("Session Name");
```
This profiles into a file that can be opened in Chrome tracing to view the benchmarking results
```
START_CONSOLE_SESSION("Session Name");
```
This writes the benchmarked readings into the console.

##### To profile any function in your benchmark while your session is active, add this function in the beginning of the code of your function
##### To profile any function in your benchmark while your session is active, add this function in the beginning of the code of your function
```
PROFILE_FUNCTION();
or
Expand Down Expand Up @@ -38,11 +43,11 @@ int fibonacci(int number) {
int main() {
int number;
std::cin >> number;
START_SESSION("Fibonacci"); //starting the session from where benchmarking starts
START_BENCHMARK_SESSION("Fibonacci"); //starting the session from where benchmarking starts

std::cout << fibonacci(number) << std::endl; //this code will be benchmarked

END_SESSION(); //ending the session
END_BENCHMARK_SESSION(); //ending the session
}
```

Expand Down
23 changes: 23 additions & 0 deletions benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "Benchmark.h"


std::once_flag IInstrumentor::_creation_once_flag;
IInstrumentor* IInstrumentor::instance = nullptr;

IInstrumentor& IInstrumentor::Get() {
if(instance) return *instance;

throw std::exception("Instrumentor instance not created");
}

IInstrumentor& IInstrumentor::Create(bool output_to_console) {
std::call_once(_creation_once_flag,
[output_to_console]() {
if (output_to_console)
instance = new ConsoleInstrumentator();
else
instance = new FilestreamInstrumentor();
}
); //thread safe initialization
return *instance;
}
107 changes: 84 additions & 23 deletions benchmark.h
Original file line number Diff line number Diff line change
@@ -1,50 +1,85 @@
#pragma once

/*
* This header only library was taken from
* https://github.com/DefinitelyNotAnmol/VisualBenchmarking/blob/master/benchmark.h
* And customized to add an option of profiling output to console using polymorphism
* Customized version : https://github.com/mhdshameel/VisualBenchmarking
* */

#define ON 1
#define OFF 0

#ifndef BENCHMARKING
#define BENCHMARKING ON
#endif // BENCHMARKING

#include <string>
#include <chrono>
#include <algorithm>
#include <fstream>
#include <mutex>
#include <algorithm>
#include <iostream>

struct ProfileResult {
std::string Name;
long long Start, End;
ProfileResult(const char* name, long long start, long long end)
ProfileResult(const char* name, long long start, long long end)
: Name(name), Start(start), End(end) {}
};

struct InstrumentationSession {
std::string Name;
};

class Instrumentor {
class IInstrumentor
{
private:
static IInstrumentor* instance;
static std::once_flag _creation_once_flag;
public:
IInstrumentor() : m_CurrentSession(nullptr) {}
InstrumentationSession* m_CurrentSession;

virtual ~IInstrumentor() {}
virtual void EndSession() = 0;
virtual void BeginSession(const std::string& name) = 0;
virtual void WriteProfile(const ProfileResult& result) = 0;

static IInstrumentor& Get();
static IInstrumentor& Create(bool output_to_console = false);

void SetCurrentSessionName(const std::string& name)
{
m_CurrentSession = new InstrumentationSession;
m_CurrentSession->Name = name;
}
};

class FilestreamInstrumentor : public IInstrumentor {
std::ofstream m_OutputStream;
int m_ProfileCount;
const std::string filepath = "results.json";
std::mutex write_mx;

public:
Instrumentor()
: m_CurrentSession(nullptr), m_ProfileCount(0) {}

void BeginSession(const std::string& name, const std::string& filepath = "results.json") {
virtual void BeginSession(const std::string& name) {
m_OutputStream.open(filepath);
WriteHeader();
m_CurrentSession = new InstrumentationSession;
m_CurrentSession->Name = name;
__super::SetCurrentSessionName(name);
}

void EndSession() {
virtual void EndSession() {
WriteFooter();
m_OutputStream.close();
delete m_CurrentSession;
m_CurrentSession = nullptr;
m_ProfileCount = 0;
}

void WriteProfile(const ProfileResult& result) {
virtual void WriteProfile(const ProfileResult& result) {
std::unique_lock<std::mutex> lk(write_mx);
if (m_ProfileCount++ > 0)
m_OutputStream << ",";

Expand Down Expand Up @@ -73,10 +108,30 @@ class Instrumentor {
m_OutputStream << "]}";
m_OutputStream.flush();
}
};

class ConsoleInstrumentator : public IInstrumentor {
std::mutex cout_mx;
public:
ConsoleInstrumentator() {}

virtual void BeginSession(const std::string& name) {
SetCurrentSessionName(name);
}

virtual void EndSession() {
delete m_CurrentSession;
m_CurrentSession = nullptr;
}

static Instrumentor& Get() {
static Instrumentor* instance = new Instrumentor();
return *instance;
virtual void WriteProfile(const ProfileResult& result) {
std::string name = result.Name;
std::replace(name.begin(), name.end(), '"', '\'');
auto lk = std::unique_lock<std::mutex> (cout_mx);
std::cout << "name: " << name << ", ";
std::cout << "dur: " << std::chrono::microseconds(result.End - result.Start).count() << "us, ";
std::cout << "ts: " << result.Start;
std::cout << std::endl;
}
};

Expand All @@ -101,20 +156,26 @@ class InstrumentationTimer {

long long start = std::chrono::time_point_cast<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count();
long long end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint).time_since_epoch().count();
Instrumentor::Get().WriteProfile(ProfileResult(m_Name, start, end));

IInstrumentor::Get().WriteProfile(ProfileResult(m_Name, start, end));

m_Stopped = true;
}
};

#if BENCHMARKING
#define PROFILE_SCOPE(name) InstrumentationTimer timer(name)
#define START_SESSION(name) Instrumentor::Get().BeginSession(name)
#define END_SESSION() Instrumentor::Get().EndSession()
#define PROFILE_FUNCTION() PROFILE_SCOPE(__FUNCTION__)
#define PROFILE_FUNCTION_DETAILED() PROFILE_SCOPE(__PRETTY_FUNCTION__)
#define PROFILE_SCOPE(name) InstrumentationTimer timer(name)
#define START_BENCHMARK_SESSION(name) IInstrumentor::Create(false).BeginSession(name)
#define START_CONSOLE_SESSION(name) IInstrumentor::Create(true).BeginSession(name)
#define END_BENCHMARK_SESSION() IInstrumentor::Get().EndSession()
#define PROFILE_FUNCTION() PROFILE_SCOPE(__FUNCTION__)
#define PROFILE_FUNCTION_DETAILED() PROFILE_SCOPE(__PRETTY_FUNCTION__)
#else
#define PROFILE_FUNCTION()
#define PROFILE_FUNCTION_DETAILED()
#endif
#define START_SESSION(name)
#define PROFILE_SCOPE(name)
#define PROFILE_FUNCTION()
#define PROFILE_FUNCTION_DETAILED()
#define START_CONSOLE_SESSION(name)
#define END_SESSION()
#endif