9 #ifndef zakero_Profiler_h
10 #define zakero_Profiler_h
264 #include <filesystem>
272 #include <experimental/source_location>
284 #ifdef ZAKERO_PROFILER_ENABLE
336 #define ZAKERO_PROFILER_INIT(output_, meta_data_...) \
337 zakero::Profiler::init(output_, ##meta_data_);
384 #define ZAKERO_PROFILER_ACTIVATE \
385 zakero::Profiler::activate();
394 #define ZAKERO_PROFILER_DEACTIVATE \
395 zakero::Profiler::deactivate();
449 #define ZAKERO_PROFILER_COMPLETE(category_, name_, meta_data_...) \
450 zakero::Profiler::Complete ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
453 , std::experimental::source_location::current() \
508 #define ZAKERO_PROFILER_DURATION(category_, name_, meta_data_...) \
509 zakero::Profiler::Duration ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
512 , std::experimental::source_location::current() \
536 #define ZAKERO_PROFILER_INSTANT(category_, name_, meta_data_...) \
538 zakero::Profiler::Instant ZAKERO_CONCAT(zakero_profiler_, __LINE__) \
541 , std::experimental::source_location::current() \
548 #define ZAKERO_PROFILER_INIT(output_, meta_data_...)
549 #define ZAKERO_PROFILER_ACTIVATE
550 #define ZAKERO_PROFILER_DEACTIVATE
551 #define ZAKERO_PROFILER_COMPLETE(category_, name_, meta_data_...)
552 #define ZAKERO_PROFILER_DURATION(category_, name_, meta_data_...)
553 #define ZAKERO_PROFILER_INSTANT(category_, name_, meta_data_...)
566 using MetaData = std::map<std::string, std::string>;
571 std::string category;
573 std::experimental::source_location location;
574 std::chrono::microseconds::rep duration;
575 std::chrono::microseconds::rep time_stamp;
576 std::thread::id thread_id;
580 Data(
const char,
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
584 :
public zakero::Profiler::Data
588 Complete(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
589 ~Complete() noexcept;
593 :
public zakero::Profiler::Data
597 Duration(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
598 ~Duration() noexcept;
602 :
public zakero::Profiler::Data
604 Instant(
const std::string&,
const std::string&,
const std::experimental::source_location&, zakero::Profiler::MetaData = {}) noexcept;
608 ~Profiler() noexcept;
610 static std::error_code init(std::ostream&, zakero::Profiler::MetaData = {}) noexcept;
611 static std::error_code init(
const std::filesystem::path, zakero::Profiler::MetaData = {}) noexcept;
613 static void activate() noexcept;
614 static void deactivate() noexcept;
616 static void report(
const zakero::Profiler::Data&) noexcept;
620 std::ostream* stream;
621 std::ofstream file_output;
630 #ifdef ZAKERO_PROFILER_IMPLEMENTATION
644 #define ZAKERO_PROFILER__ERROR_DATA \
645 X(Error_None , 0 , "No Error" ) \
646 X(Error_Stream_Already_Open , 1 , "The profiler is already using an output stream" ) \
647 X(Error_No_Filename , 2 , "No filename was provided" ) \
648 X(Error_Cant_Open_Stream , 3 , "Unable to open the output stream" ) \
649 X(Error_Bad_Stream , 4 , "The stream is not in a good state" ) \
661 #define ZAKERO_PROFILER__ERROR(err_) std::error_code(err_, ProfilerErrorCategory)
665 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
680 #define ZAKERO_PROFILER_IMPLEMENTATION
692 #define ZAKERO_PROFILER_ENABLE
714 class ProfilerErrorCategory_
715 :
public std::error_category
718 constexpr ProfilerErrorCategory_() noexcept
722 const char* name()
const noexcept
override
724 return "zakero.Profiler";
727 std::string message(
int condition)
const override
731 #define X(name_, val_, mesg_) \
732 case val_: return mesg_;
733 ZAKERO_PROFILER__ERROR_DATA
737 return "Unknown error condition";
739 } ProfilerErrorCategory;
741 #define X(name_, val_, mesg_) \
742 static constexpr int name_ = val_;
743 ZAKERO_PROFILER__ERROR_DATA
746 zakero::Profiler zakero_profiler;
790 Profiler::Profiler() noexcept
804 Profiler::~Profiler() noexcept
806 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
808 if(stream !=
nullptr)
810 (*stream) <<
"]}" << std::endl;
812 if(file_output.is_open())
833 std::error_code zakero::Profiler::init(
const std::filesystem::path path
834 , zakero::Profiler::MetaData meta_data
837 if(zakero_profiler.stream !=
nullptr)
839 return ZAKERO_PROFILER__ERROR(Error_Stream_Already_Open);
842 if(path.has_filename() ==
false)
844 return ZAKERO_PROFILER__ERROR(Error_No_Filename);
847 zakero_profiler.file_output.open(path);
849 if(zakero_profiler.file_output.is_open() ==
false)
851 return ZAKERO_PROFILER__ERROR(Error_Cant_Open_Stream);
854 std::error_code error;
856 error = init(zakero_profiler.file_output, meta_data);
871 std::error_code zakero::Profiler::init(std::ostream& output_stream
872 , zakero::Profiler::MetaData meta_data
875 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
877 if(zakero_profiler.stream !=
nullptr)
879 return ZAKERO_PROFILER__ERROR(Error_Stream_Already_Open);
882 if(output_stream.good() ==
false)
884 return ZAKERO_PROFILER__ERROR(Error_Bad_Stream);
887 zakero_profiler.stream = &output_stream;
890 if(meta_data.contains(
"date") ==
false)
892 std::time_t time = std::chrono::system_clock::to_time_t(
893 std::chrono::system_clock::now()
897 std::strftime(buf,
sizeof(buf),
"%F %T", std::localtime(&time));
899 meta_data[
"date"] = buf;
902 if(meta_data.contains(
"traceEvents"))
904 meta_data.erase(
"traceEvents");
907 meta_data[
"displayTimeUnit"] =
"ms";
909 (*zakero_profiler.stream) <<
"{";
911 for(
const auto& iter : meta_data)
913 (*zakero_profiler.stream) <<
"\"" << iter.first <<
"\":\"" << iter.second <<
"\",";
916 (*zakero_profiler.stream) <<
"\"traceEvents\":[{}\n";
918 return ZAKERO_PROFILER__ERROR(Error_None);
928 void zakero::Profiler::activate() noexcept
930 zakero_profiler.is_active =
true;
943 void zakero::Profiler::deactivate() noexcept
945 zakero_profiler.is_active =
false;
954 void Profiler::report(
const zakero::Profiler::Data& data
957 std::lock_guard<std::mutex> lock(zakero_profiler.mutex);
962 (*zakero_profiler.stream)
963 <<
",{\"ph\":\"" << data.phase <<
"\""
964 <<
",\"ts\":" << data.time_stamp
965 <<
",\"dur\":" << data.duration
966 <<
",\"pid\":" << data.process_id
967 <<
",\"tid\":" << data.thread_id
968 <<
",\"cat\":\"" << data.category <<
"\""
969 <<
",\"name\":\"" << data.name <<
"\""
971 <<
"{\"file_name\":\"" << data.location.file_name() <<
"\""
972 <<
",\"function_name\":\"" << data.location.function_name() <<
"\""
974 for(
const auto& iter : data.meta_data)
976 (*zakero_profiler.stream)
977 <<
",\"" << iter.first <<
"\":\"" << iter.second <<
"\""
981 (*zakero_profiler.stream) <<
"}}\n";
1028 Profiler::Data::Data(
const char phase
1029 ,
const std::string& category
1030 ,
const std::string& name
1031 ,
const std::experimental::source_location& location
1032 , zakero::Profiler::MetaData meta_data
1034 : meta_data(meta_data)
1035 , category(category)
1037 , location(location)
1040 , thread_id(std::this_thread::get_id())
1065 Profiler::Complete::Complete(
const std::string& category
1066 ,
const std::string& name
1067 ,
const std::experimental::source_location& location
1068 , zakero::Profiler::MetaData meta_data
1070 : zakero::Profiler::Data(
'X', category, name, location, meta_data)
1071 , was_active(zakero_profiler.is_active)
1081 Profiler::Complete::~Complete() noexcept
1083 if(was_active || zakero_profiler.is_active)
1086 zakero::Profiler::report(*
this);
1109 Profiler::Duration::Duration(
const std::string& category
1110 ,
const std::string& name
1111 ,
const std::experimental::source_location& location
1112 , zakero::Profiler::MetaData meta_data
1114 : zakero::Profiler::Data(
'B', category, name, location, meta_data)
1115 , was_active(zakero_profiler.is_active)
1125 Profiler::Duration::~Duration() noexcept
1127 if(was_active || zakero_profiler.is_active)
1129 zakero::Profiler::report(*
this);
1133 zakero::Profiler::report(*
this);
1156 Profiler::Instant::Instant(
const std::string& category
1157 ,
const std::string& name
1158 ,
const std::experimental::source_location& location
1159 , zakero::Profiler::MetaData meta_data
1161 : zakero::Profiler::Data(
'i', category, name, location, meta_data)
1163 if(zakero_profiler.is_active)
1165 zakero::Profiler::report(*
this);
#define ZAKERO_STEADY_TIME_NOW(unit_)
Get the current time.
Definition: Zakero_Base.h:231
#define ZAKERO_PID
Get the Process Id.
Definition: Zakero_Base.h:212