9 #ifndef zakero_Profiler_h
10 #define zakero_Profiler_h
256 #include <filesystem>
264 #include <experimental/source_location>
276 #ifdef ZAKERO_PROFILER_ENABLE
328 #define ZAKERO_PROFILER_INIT(output_, meta_data_...) \
329 zakero::Profiler::init(output_, ##meta_data_);
376 #define ZAKERO_PROFILER_ACTIVATE \
377 zakero::Profiler::activate();
386 #define ZAKERO_PROFILER_DEACTIVATE \
387 zakero::Profiler::deactivate();
441 #define ZAKERO_PROFILER_COMPLETE(category_, name_, meta_data_...) \
442 zakero::Profiler::Complete ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
445 , std::experimental::source_location::current() \
500 #define ZAKERO_PROFILER_DURATION(category_, name_, meta_data_...) \
501 zakero::Profiler::Duration ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
504 , std::experimental::source_location::current() \
528 #define ZAKERO_PROFILER_INSTANT(category_, name_, meta_data_...) \
530 zakero::Profiler::Instant ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
533 , std::experimental::source_location::current() \
540 #define ZAKERO_PROFILER_INIT(output_, meta_data_...)
541 #define ZAKERO_PROFILER_ACTIVATE
542 #define ZAKERO_PROFILER_DEACTIVATE
543 #define ZAKERO_PROFILER_COMPLETE(category_, name_, meta_data_...)
544 #define ZAKERO_PROFILER_DURATION(category_, name_, meta_data_...)
545 #define ZAKERO_PROFILER_INSTANT(category_, name_, meta_data_...)
558 using MetaData = std::map<std::string, std::string>;
563 std::string category;
565 std::experimental::source_location location;
566 std::chrono::microseconds::rep duration;
567 std::chrono::microseconds::rep time_stamp;
568 std::thread::id thread_id;
572 Data(
const char,
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
576 :
public zakero::Profiler::Data
580 Complete(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
581 ~Complete() noexcept;
585 :
public zakero::Profiler::Data
589 Duration(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
590 ~Duration() noexcept;
594 :
public zakero::Profiler::Data
596 Instant(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
600 ~Profiler() noexcept;
602 static std::error_code init(std::ostream&, zakero::Profiler::MetaData = {}) noexcept;
603 static std::error_code init(
const std::filesystem::path, zakero::Profiler::MetaData = {}) noexcept;
605 static void activate() noexcept;
606 static void deactivate() noexcept;
608 static void report(
const zakero::Profiler::Data&) noexcept;
612 std::ostream* stream;
613 std::ofstream file_output;
622 #ifdef ZAKERO_PROFILER_IMPLEMENTATION
636 #define ZAKERO_PROFILER__ERROR_DATA \
637 X(Error_None , 0 , "No Error" ) \
638 X(Error_Stream_Already_Open , 1 , "The profiler is already using an output stream" ) \
639 X(Error_No_Filename , 2 , "No filename was provided" ) \
640 X(Error_Cant_Open_Stream , 3 , "Unable to open the output stream" ) \
641 X(Error_Bad_Stream , 4 , "The stream is not in a good state" ) \
653 #define ZAKERO_PROFILER__ERROR(err_) std::error_code(err_, ProfilerErrorCategory)
657 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
672 #define ZAKERO_PROFILER_IMPLEMENTATION
684 #define ZAKERO_PROFILER_ENABLE
706 class ProfilerErrorCategory_
707 :
public std::error_category
710 constexpr ProfilerErrorCategory_() noexcept
714 const char* name()
const noexcept
override
716 return "zakero.Profiler";
719 std::string message(
int condition)
const override
723 #define X(name_, val_, mesg_) \
724 case val_: return mesg_;
725 ZAKERO_PROFILER__ERROR_DATA
729 return "Unknown error condition";
731 } ProfilerErrorCategory;
733 #define X(name_, val_, mesg_) \
734 static constexpr int name_ = val_;
735 ZAKERO_PROFILER__ERROR_DATA
738 zakero::Profiler zakero_profiler;
782 Profiler::Profiler() noexcept
796 Profiler::~Profiler() noexcept
798 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
800 if(stream !=
nullptr)
802 (*stream) <<
"]}" << std::endl;
804 if(file_output.is_open())
825 std::error_code zakero::Profiler::init(
const std::filesystem::path path
826 , zakero::Profiler::MetaData meta_data
829 if(zakero_profiler.stream !=
nullptr)
831 return ZAKERO_PROFILER__ERROR(Error_Stream_Already_Open);
834 if(path.has_filename() ==
false)
836 return ZAKERO_PROFILER__ERROR(Error_No_Filename);
839 zakero_profiler.file_output.open(path);
841 if(zakero_profiler.file_output.is_open() ==
false)
843 return ZAKERO_PROFILER__ERROR(Error_Cant_Open_Stream);
846 std::error_code error;
848 error = init(zakero_profiler.file_output, meta_data);
863 std::error_code zakero::Profiler::init(std::ostream& output_stream
864 , zakero::Profiler::MetaData meta_data
867 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
869 if(zakero_profiler.stream !=
nullptr)
871 return ZAKERO_PROFILER__ERROR(Error_Stream_Already_Open);
874 if(output_stream.good() ==
false)
876 return ZAKERO_PROFILER__ERROR(Error_Bad_Stream);
879 zakero_profiler.stream = &output_stream;
882 if(meta_data.contains(
"date") ==
false)
884 std::time_t time = std::chrono::system_clock::to_time_t(
885 std::chrono::system_clock::now()
889 std::strftime(buf,
sizeof(buf),
"%F %T", std::localtime(&time));
891 meta_data[
"date"] = buf;
894 if(meta_data.contains(
"traceEvents"))
896 meta_data.erase(
"traceEvents");
899 meta_data[
"displayTimeUnit"] =
"ms";
901 (*zakero_profiler.stream) <<
"{";
903 for(
const auto& iter : meta_data)
905 (*zakero_profiler.stream) <<
"\"" << iter.first <<
"\":\"" << iter.second <<
"\",";
908 (*zakero_profiler.stream) <<
"\"traceEvents\":[{}\n";
910 return ZAKERO_PROFILER__ERROR(Error_None);
920 void zakero::Profiler::activate() noexcept
922 zakero_profiler.is_active =
true;
935 void zakero::Profiler::deactivate() noexcept
937 zakero_profiler.is_active =
false;
946 void Profiler::report(
const zakero::Profiler::Data& data
949 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
954 (*zakero_profiler.stream)
955 <<
",{\"ph\":\"" << data.phase <<
"\""
956 <<
",\"ts\":" << data.time_stamp
957 <<
",\"dur\":" << data.duration
958 <<
",\"pid\":" << data.process_id
959 <<
",\"tid\":" << data.thread_id
960 <<
",\"cat\":\"" << data.category <<
"\""
961 <<
",\"name\":\"" << data.name <<
"\""
963 <<
"{\"file_name\":\"" << data.location.file_name() <<
"\""
964 <<
",\"function_name\":\"" << data.location.function_name() <<
"\""
966 for(
const auto& iter : data.meta_data)
968 (*zakero_profiler.stream)
969 <<
",\"" << iter.first <<
"\":\"" << iter.second <<
"\""
973 (*zakero_profiler.stream) <<
"}}\n";
1020 Profiler::Data::Data(
const char phase
1021 ,
const std::string& category
1022 ,
const std::string& name
1023 ,
const std::experimental::source_location& location
1024 , zakero::Profiler::MetaData meta_data
1026 : meta_data(meta_data)
1027 , category(category)
1029 , location(location)
1032 , thread_id(std::this_thread::get_id())
1057 Profiler::Complete::Complete(
const std::string& category
1058 ,
const std::string& name
1059 ,
const std::experimental::source_location& location
1060 , zakero::Profiler::MetaData meta_data
1062 : zakero::Profiler::Data(
'X', category, name, location, meta_data)
1063 , was_active(zakero_profiler.is_active)
1073 Profiler::Complete::~Complete() noexcept
1075 if(was_active || zakero_profiler.is_active)
1078 zakero::Profiler::report(*
this);
1101 Profiler::Duration::Duration(
const std::string& category
1102 ,
const std::string& name
1103 ,
const std::experimental::source_location& location
1104 , zakero::Profiler::MetaData meta_data
1106 : zakero::Profiler::Data(
'B', category, name, location, meta_data)
1107 , was_active(zakero_profiler.is_active)
1117 Profiler::Duration::~Duration() noexcept
1119 if(was_active || zakero_profiler.is_active)
1121 zakero::Profiler::report(*
this);
1125 zakero::Profiler::report(*
this);
1148 Profiler::Instant::Instant(
const std::string& category
1149 ,
const std::string& name
1150 ,
const std::experimental::source_location& location
1151 , zakero::Profiler::MetaData meta_data
1153 : zakero::Profiler::Data(
'i', category, name, location, meta_data)
1155 if(zakero_profiler.is_active)
1157 zakero::Profiler::report(*
this);
#define ZAKERO_STEADY_TIME_NOW(unit_)
Get the current time.
Definition: Zakero_Base.h:205
#define ZAKERO_PID
Get the Process Id.
Definition: Zakero_Base.h:187