/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Autogenerated file -- DO NOT EDIT! #ifndef PANDA_EVENTS_GEN_H #define PANDA_EVENTS_GEN_H #include "macros.h" #include "os/mutex.h" #include "utils/list.h" #include "runtime/include/mem/panda_string.h" #include #include #include namespace panda { namespace events { % EventsData.events.each do |event| % event.fields.select(&:is_enum?).each do |field| enum class <%= field.type %> { <%= field.enums.map(&:upcase).join(', ') %> }; % end % end class EventsBase { public: EventsBase() = default; virtual ~EventsBase() = default; NO_COPY_SEMANTIC(EventsBase); NO_MOVE_SEMANTIC(EventsBase); % EventsData.events.each do |event| virtual void <%= event.name.camelize %>(<%= event.fields.map {|f| f.arg_type}.join(', ') %>) {} // NOLINT % end auto& GetLock() { return lock_; } private: os::memory::Mutex lock_; }; % EventsData.events.each do |event| % event.fields.select(&:is_enum?).each do |field| inline std::ostream& operator<<(std::ostream& os, <%= field.type %> field) { switch (field) { % field.enums.each do |enum| case <%= field.type %>::<%= enum.upcase %>: os << "<%= enum.upcase %>"; break; % end } return os; } % end % end class EventsMemory : public events::EventsBase { public: % EventsData.events.each do |event| struct <%= event.name.camelize %>Event{ % event.fields.each do |field| <%= field.type %> <%= field.name %>; % end }; % end // NOLINTNEXTLINE(fuchsia-multiple-inheritance) struct EventRecord : public ListNode, public std::variant<<%= EventsData.events.map{|e| e.name.camelize + 'Event'}.join(', ') %>> { using VariantBase = std::variant<<%= EventsData.events.map{|e| e.name.camelize + 'Event'}.join(', ') %>>; % EventsData.events.each do |event| explicit EventRecord(<%= event.name.camelize %>Event v) : VariantBase(v) {} % end }; public: EventsMemory() = default; ~EventsMemory() override { os::memory::LockHolder lock(GetLock()); for (auto it = event_list_.begin(); it != event_list_.end(); ) { delete &*(it++); } } NO_COPY_SEMANTIC(EventsMemory); NO_MOVE_SEMANTIC(EventsMemory); % EventsData.events.each do |event| void <%= event.name.camelize %>(<%= event.fields.map {|f| f.arg_type + ' ' + f.name }.join(', ') %>) override { os::memory::LockHolder lock(GetLock()); auto event = new EventRecord(<%= event.name.camelize %>Event{<%= event.fields.map(&:name).join(', ') %>}); last_ = event_list_.InsertAfter(last_, *event); } % end template void EnumerateEvents(Func func) { os::memory::LockHolder lock(GetLock()); for (const auto& event : event_list_) { if(auto p = std::get_if(&event)) { func(static_cast(*p)); } } } template bool Find(Comp cmp) { bool found = false; EnumerateEvents([&found, &cmp](const auto& event) { if (cmp(event)) { found = true; return false; } return true; }); return found; } template std::vector Select([[maybe_unused]] F pred = false) { std::vector res; if constexpr (std::is_same_v) { EnumerateEvents([&res](const auto& event) { res.push_back(&event); }); } else { EnumerateEvents([&pred, &res](const auto& event) { if (pred(&event)) { res.push_back(&event); } }); } return res; } private: List event_list_ GUARDED_BY(GetLock()); List::Iterator last_{event_list_.before_begin()}; }; class EventsCsv : public events::EventsBase { public: EventsCsv() { file_.open("events.csv"); } explicit EventsCsv(std::string_view path) { file_.open(path.data()); } ~EventsCsv() override { os::memory::LockHolder lock(GetLock()); file_.close(); } NO_COPY_SEMANTIC(EventsCsv); NO_MOVE_SEMANTIC(EventsCsv); % EventsData.events.each do |event| void <%= event.name.camelize %>(<%= event.fields.map {|f| f.arg_type + ' ' + f.name }.join(', ') %>) override { os::memory::LockHolder lock(GetLock()); file_ << "<%= event.name.camelize %>," << <%= event.fields.map(&:name).join(" << ',' << ") %> << std::endl; } % end private: std::ofstream file_ GUARDED_BY(GetLock()); }; class EventsLog : public events::EventsBase { public: EventsLog() { Logger::EnableComponent(Logger::EVENTS); } ~EventsLog() override { Logger::DisableComponent(Logger::EVENTS); } NO_COPY_SEMANTIC(EventsLog); NO_MOVE_SEMANTIC(EventsLog); % EventsData.events.each do |event| void <%= event.name.camelize %>(<%= event.fields.map {|f| f.arg_type + ' ' + f.name }.join(', ') %>) override { LOG(INFO, EVENTS) << "<%= event.name.camelize %>," << <%= event.fields.map(&:name).join(" << ',' << ") %>; } % end }; } // namespace events class Events { public: enum StreamKind { CSV, MEMORY, LOG }; template static void Create(Args&&... args) { if constexpr (kind == StreamKind::CSV) { // NOLINT pevents = new events::EventsCsv(std::forward(args)...); } else if constexpr (kind == StreamKind::MEMORY) { // NOLINT pevents = new events::EventsMemory; } else if constexpr (kind == StreamKind::LOG) { // NOLINT pevents = new events::EventsLog; } else { // NOLINT UNREACHABLE(); } } template static void Create(std::string_view output, Args&&... args) { if (output == "csv") { pevents = new events::EventsCsv(std::forward(args)...); } else if (output == "memory") { pevents = new events::EventsMemory; } else if (output == "log") { pevents = new events::EventsLog; } else { // NOLINT UNREACHABLE(); } } static void Destroy() { delete pevents; pevents = nullptr; } template static auto CastTo() { if constexpr (kind == StreamKind::CSV) { // NOLINT return static_cast(pevents); } else if constexpr (kind == StreamKind::MEMORY) { // NOLINT return static_cast(pevents); } else { // NOLINT UNREACHABLE(); } } static bool IsEnabled() { return pevents != nullptr; } static events::EventsBase* GetEvents() { return pevents; } private: static inline events::EventsBase* pevents{nullptr}; }; #ifndef NDEBUG #define PANDA_EVENTS_ENABLED % EventsData.events.each do |event| % if !event.enable? // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EVENT_<%= event.name.upcase %>_ENABLED 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EVENT_<%= event.name.upcase %>(<%= event.fields.map(&:name).join(', ') %>) % else // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EVENT_<%= event.name.upcase %>_ENABLED 1 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EVENT_<%= event.name.upcase %>(<%= event.fields.map(&:name).join(', ') %>) \ if (Events::IsEnabled()) { \ Events::GetEvents()-><%= event.name.camelize %>(<%= event.fields.map(&:name).join(', ') %>); \ } % end % end #else % EventsData.events.each do |event| // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EVENT_<%= event.name.upcase %>(<%= event.fields.map(&:name).join(', ') %>) % end #endif } // namespace panda #endif // PANDA_EVENTS_GEN_H