diff --git a/src/libs/nanotrace/nanotracehr.cpp b/src/libs/nanotrace/nanotracehr.cpp index 7be78cf6a4d..4837cfe9787 100644 --- a/src/libs/nanotrace/nanotracehr.cpp +++ b/src/libs/nanotrace/nanotracehr.cpp @@ -4,13 +4,17 @@ #include "nanotracehr.h" #include +#include #include #include -#include #include #include +#ifdef Q_OS_UNIX +# include +#endif + namespace NanotraceHR { namespace { @@ -18,11 +22,50 @@ namespace { template void printEvent(std::ostream &out, const TraceEvent &event, qint64 processId, std::thread::id threadId) { - out << R"({"ph":"X","name":")" << event.name << R"(","cat":")" << event.category - << R"(","ts":")" << static_cast(event.start.time_since_epoch().count()) / 1000 - << R"(","dur":")" << static_cast(event.duration.count()) / 1000 << R"(","pid":")" - << processId << R"(","tid":")" << threadId << R"(","args":)" << event.arguments << "}"; + out << R"({"ph":")" << event.type << R"(","name":")" << event.name << R"(","cat":")" + << event.category << R"(","ts":")" + << static_cast(event.time.time_since_epoch().count()) / 1000 << R"(","pid":")" + << processId << R"(","tid":")" << threadId << R"(")"; + + if (event.type == 'X') + out << R"(,"dur":)" << static_cast(event.duration.count()) / 1000; + + if (event.id != 0) + out << R"(,"id":)" << event.id; + + if (event.arguments.size()) + out << R"(,"args":)" << event.arguments; + + out << "}"; } + +void writeMetaEvent(TraceFile *file, std::string_view key, std::string_view value) +{ + std::lock_guard lock{file->fileMutex}; + auto &out = file->out; + + if (out.is_open()) { + file->out << R"({"name":")" << key << R"(","ph":"M", "pid":")" + << QCoreApplication::applicationPid() << R"(","tid":")" + << std::this_thread::get_id() << R"(","args":{"name":")" << value << R"("}})" + << ",\n"; + } +} + +std::string getThreadName() +{ + std::array buffer; + buffer[0] = 0; +#ifdef Q_OS_UNIX + auto rc = pthread_getname_np(pthread_self(), buffer.data(), buffer.size()); + if (rc != 0) + return {}; + +#endif + + return buffer.data(); +} + } // namespace template @@ -42,7 +85,6 @@ void flushEvents(const Utils::span events, printEvent(out, event, processId, threadId); out << ",\n"; } - out << std::flush; } } @@ -57,8 +99,12 @@ void openFile(EnabledTraceFile &file) { std::lock_guard lock{file.fileMutex}; - if (file.out = std::ofstream{file.filePath, std::ios::trunc}; file.out.good()) + if (file.out = std::ofstream{file.filePath, std::ios::trunc}; file.out.good()) { file.out << std::fixed << std::setprecision(3) << R"({"traceEvents": [)"; + file.out << R"({"name":"process_name","ph":"M", "pid":)" + << QCoreApplication::applicationPid() << R"(,"args":{"name":"QtCreator"}})" + << ",\n"; + } } void finalizeFile(EnabledTraceFile &file) @@ -109,4 +155,45 @@ EnabledEventQueue &globalEventQueue() return s_globalEventQueue; } +template +EventQueue::EventQueue(EnabledTraceFile *file, + TraceEventsSpan eventsOne, + TraceEventsSpan eventsTwo) + : file{file} + , eventsOne{eventsOne} + , eventsTwo{eventsTwo} + , currentEvents{eventsOne} +{ + if (auto thread = QThread::currentThread()) { + connection = QObject::connect(QCoreApplication::instance(), + &QCoreApplication::aboutToQuit, + thread, + [&] { flush(); }); + auto name = getThreadName(); + if (name.size()) { + writeMetaEvent(file, "thread_name", name); + } + } +} + +template +EventQueue::~EventQueue() +{ + flush(); + if (connection) + QObject::disconnect(connection); +} + +template +void EventQueue::flush() +{ + std::lock_guard lock{mutex}; + if (isEnabled == IsEnabled::Yes && eventsIndex > 0) { + flushEvents(currentEvents.subspan(0, eventsIndex), std::this_thread::get_id(), *this); + eventsIndex = 0; + } +} + +template class NANOTRACE_EXPORT EventQueue; +template class NANOTRACE_EXPORT EventQueue; } // namespace NanotraceHR diff --git a/src/libs/nanotrace/nanotracehr.h b/src/libs/nanotrace/nanotracehr.h index ee8ff808dc8..e2ec3823b9d 100644 --- a/src/libs/nanotrace/nanotracehr.h +++ b/src/libs/nanotrace/nanotracehr.h @@ -7,7 +7,10 @@ #include +#include + #include +#include #include #include #include @@ -33,15 +36,34 @@ constexpr bool isTracerActive() #endif } -template -std::string_view toStringView(Utils::span string) +namespace Literals { +struct TracerLiteral { - return {string.data(), string.size()}; -} + friend constexpr TracerLiteral operator""_t(const char *text, size_t size); + constexpr operator std::string_view() const { return text; } + +private: + constexpr TracerLiteral(std::string_view text) + : text{text} + {} + + std::string_view text; +}; + +constexpr TracerLiteral operator""_t(const char *text, size_t size) +{ + return {std::string_view{text, size}}; +} +} // namespace Literals + +using namespace Literals; template struct TraceEvent { + using StringType = String; + using ArgumentType = std::conditional_t, TracerLiteral, String>; + TraceEvent() = default; TraceEvent(const TraceEvent &) = delete; TraceEvent(TraceEvent &&) = delete; @@ -52,8 +74,10 @@ struct TraceEvent String name; String category; String arguments; - TimePoint start; + TimePoint time; Duration duration; + std::size_t id = 0; + char type = ' '; }; using StringViewTraceEvent = TraceEvent; @@ -126,7 +150,10 @@ public: template class EventQueue -{}; +{ +public: + using IsActive = std::false_type; +}; template class EventQueue @@ -134,15 +161,13 @@ class EventQueue using TraceEventsSpan = Utils::span; public: - EventQueue() = default; + using IsActive = std::true_type; - ~EventQueue() - { - if (isEnabled == IsEnabled::Yes && eventsIndex > 0) { - flushEvents(currentEvents.subspan(0, eventsIndex), std::this_thread::get_id(), *this); - eventsIndex = 0; - } - } + EventQueue(EnabledTraceFile *file, TraceEventsSpan eventsOne, TraceEventsSpan eventsTwo); + + ~EventQueue(); + + void flush(); EventQueue(const EventQueue &) = delete; EventQueue(EventQueue &&) = delete; @@ -154,14 +179,17 @@ public: TraceEventsSpan eventsTwo; TraceEventsSpan currentEvents; std::size_t eventsIndex = 0; - IsEnabled isEnabled = IsEnabled::No; + IsEnabled isEnabled = IsEnabled::Yes; + QMetaObject::Connection connection; + std::mutex mutex; }; +extern template class NANOTRACE_EXPORT EventQueue; +extern template class NANOTRACE_EXPORT EventQueue; + template class EventQueueData { - using TraceEvents = std::array; - public: using IsActive = Enabled; @@ -197,7 +225,7 @@ struct EventQueueDataPointer EnabledEventQueue createEventQueue() const { if constexpr (isTracerActive()) { - return {&data->file, data->eventsOne, data->eventsTwo, data->eventsOne, 0, IsEnabled::Yes}; + return {&data->file, data->eventsOne, data->eventsTwo}; } else { return {}; } @@ -229,38 +257,63 @@ TraceEvent &getTraceEvent(EnabledEventQueue &eventQueue) return eventQueue.currentEvents[eventQueue.eventsIndex++]; } -namespace Literals { -struct TracerLiteral +template +class Token { - friend constexpr TracerLiteral operator""_t(const char *text, size_t size); +public: + using IsActive = std::false_type; - constexpr operator std::string_view() const { return text; } + constexpr std::size_t operator*() const { return 0; } -private: - constexpr TracerLiteral(std::string_view text) - : text{text} - {} + constexpr explicit operator bool() const { return false; } - std::string_view text; + static constexpr bool isActive() { return false; } }; -constexpr TracerLiteral operator""_t(const char *text, size_t size) -{ - return {std::string_view{text, size}}; -} -} // namespace Literals +template +class Category; -using namespace Literals; +template<> +class Token +{ + friend Category; + friend Category; + + Token(std::size_t id) + : m_id{id} + {} + +public: + using IsActive = std::true_type; + + constexpr std::size_t operator*() const { return m_id; } + + constexpr explicit operator bool() const { return m_id; } + + static constexpr bool isActive() { return true; } + +private: + std::size_t m_id; +}; template class Category { public: using IsActive = std::false_type; + using ArgumentType = typename TraceEvent::ArgumentType; - Category(TracerLiteral, EventQueue &) {} + Category(ArgumentType, EventQueue &) {} - Category(TracerLiteral, EventQueue &) {} + Category(ArgumentType, EventQueue &) {} + + Token beginAsynchronous(ArgumentType) { return {}; } + + void tickAsynchronous(Token, ArgumentType) {} + + void endAsynchronous(Token, ArgumentType) {} + + static constexpr bool isActive() { return false; } }; template @@ -268,8 +321,67 @@ class Category { public: using IsActive = std::true_type; - TracerLiteral name; - EnabledEventQueue &eventQueue; + using ArgumentType = typename TraceEvent::ArgumentType; + using StringType = typename TraceEvent::StringType; + + template + Category(ArgumentType name, EventQueue &queue) + : m_name{std::move(name)} + , m_eventQueue{queue} + { + static_assert(std::is_same_v, + "A active category is not possible with an inactive event queue!"); + } + + Token beginAsynchronous(ArgumentType traceName) + { + auto id = ++idCounter; + auto &traceEvent = getTraceEvent(m_eventQueue); + traceEvent.name = std::move(traceName); + traceEvent.category = m_name; + traceEvent.time = Clock::now(); + traceEvent.type = 'b'; + traceEvent.id = id; + + return id; + } + + void tickAsynchronous(Token token, ArgumentType traceName) + { + if (!token) + return; + + auto &traceEvent = getTraceEvent(m_eventQueue); + traceEvent.name = std::move(traceName); + traceEvent.category = m_name; + traceEvent.time = Clock::now(); + traceEvent.type = 'n'; + traceEvent.id = *token; + } + + void endAsynchronous(Token token, ArgumentType traceName) + { + if (!token) + return; + + auto &traceEvent = getTraceEvent(m_eventQueue); + traceEvent.name = std::move(traceName); + traceEvent.category = m_name; + traceEvent.time = Clock::now(); + traceEvent.type = 'e'; + traceEvent.id = *token; + } + + EnabledEventQueue &eventQueue() const { return m_eventQueue; } + + std::string_view name() const { return m_name; } + + static constexpr bool isActive() { return true; } + +private: + StringType m_name; + EnabledEventQueue &m_eventQueue; + inline static std::atomic idCounter = 0; }; template @@ -277,18 +389,15 @@ using StringViewCategory = Category; template using StringCategory = Category; -class DisabledCategory -{ - using IsActive = std::false_type; -}; - template class Tracer { public: - constexpr Tracer(TracerLiteral, Category &, TracerLiteral) {} + using ArgumentType = typename Category::ArgumentType; - constexpr Tracer(TracerLiteral, Category &) {} + constexpr Tracer(ArgumentType, Category &, ArgumentType) {} + + constexpr Tracer(ArgumentType, Category &) {} ~Tracer() {} }; @@ -297,22 +406,22 @@ template<> class Tracer> { public: - constexpr Tracer(TracerLiteral name, StringViewCategory &category, TracerLiteral arguments) + Tracer(TracerLiteral name, StringViewCategory &category, TracerLiteral arguments) : m_name{name} , m_arguments{arguments} , m_category{category} { if constexpr (isTracerActive()) { - if (category.eventQueue.isEnabled == IsEnabled::Yes) + if (category.eventQueue().isEnabled == IsEnabled::Yes) m_start = Clock::now(); } } - constexpr Tracer(TracerLiteral name, StringViewCategory &category) - : Tracer{name, category, "{}"_t} + Tracer(TracerLiteral name, StringViewCategory &category) + : Tracer{name, category, ""_t} { if constexpr (isTracerActive()) { - if (category.eventQueue.isEnabled == IsEnabled::Yes) + if (category.eventQueue().isEnabled == IsEnabled::Yes) m_start = Clock::now(); } } @@ -320,14 +429,15 @@ public: ~Tracer() { if constexpr (isTracerActive()) { - if (m_category.eventQueue.isEnabled == IsEnabled::Yes) { + if (m_category.eventQueue().isEnabled == IsEnabled::Yes) { auto duration = Clock::now() - m_start; - auto &traceEvent = getTraceEvent(m_category.eventQueue); + auto &traceEvent = getTraceEvent(m_category.eventQueue()); traceEvent.name = m_name; - traceEvent.category = m_category.name; + traceEvent.category = m_category.name(); traceEvent.arguments = m_arguments; - traceEvent.start = m_start; + traceEvent.time = m_start; traceEvent.duration = duration; + traceEvent.type = 'X'; } } } @@ -349,16 +459,16 @@ public: , m_category{category} { if constexpr (isTracerActive()) { - if (category.eventQueue.isEnabled == IsEnabled::Yes) + if (category.eventQueue().isEnabled == IsEnabled::Yes) m_start = Clock::now(); } } Tracer(std::string name, StringViewCategory &category) - : Tracer{std::move(name), category, "{}"} + : Tracer{std::move(name), category, ""} { if constexpr (isTracerActive()) { - if (category.eventQueue.isEnabled == IsEnabled::Yes) + if (category.eventQueue().isEnabled == IsEnabled::Yes) m_start = Clock::now(); } } @@ -366,14 +476,15 @@ public: ~Tracer() { if constexpr (isTracerActive()) { - if (m_category.eventQueue.isEnabled == IsEnabled::Yes) { + if (m_category.eventQueue().isEnabled == IsEnabled::Yes) { auto duration = Clock::now() - m_start; - auto &traceEvent = getTraceEvent(m_category.eventQueue); + auto &traceEvent = getTraceEvent(m_category.eventQueue()); traceEvent.name = std::move(m_name); - traceEvent.category = m_category.name; + traceEvent.category = m_category.name(); traceEvent.arguments = std::move(m_arguments); - traceEvent.start = m_start; + traceEvent.time = m_start; traceEvent.duration = duration; + traceEvent.type = 'X'; } } } @@ -403,7 +514,7 @@ public: } GlobalTracer(std::string name, std::string category) - : GlobalTracer{std::move(name), std::move(category), "{}"} + : GlobalTracer{std::move(name), std::move(category), ""} {} ~GlobalTracer() @@ -415,8 +526,9 @@ public: traceEvent.name = std::move(m_name); traceEvent.category = std::move(m_category); traceEvent.arguments = std::move(m_arguments); - traceEvent.start = std::move(m_start); + traceEvent.time = std::move(m_start); traceEvent.duration = std::move(duration); + traceEvent.type = 'X'; } } } diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 7774f9a23bc..c507b0b9d3b 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -401,8 +401,8 @@ public: const_iterator end() const & { return iterator{m_statement, false}; } private: - NanotraceHR::Tracer tracer{"range"_t, - sqliteHighLevelCategory()}; + NanotraceHR::Tracer> tracer{ + "range"_t, sqliteHighLevelCategory()}; StatementImplementation &m_statement; }; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 7b54937f181..e92dc29942f 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -16,9 +16,13 @@ option(USE_PROJECTSTORAGE "Use ProjectStorage" ${ENV_QDS_USE_PROJECTSTORAGE}) add_feature_info("ProjectStorage" ${USE_PROJECTSTORAGE} "") env_with_default("QTC_ENABLE_PROJECT_STORAGE_TRACING" ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING OFF) -option(ENABLE_PROJECT_STORAGE_TRACING "Enable sqlite tarcing" ${ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING}) +option(ENABLE_PROJECT_STORAGE_TRACING "Enable sqlite tracing" ${ENV_QTC_ENABLE_PROJECT_STORAGE_TRACING}) add_feature_info("Sqlite tracing" ${ENABLE_PROJECT_STORAGE_TRACING} "") +env_with_default("QTC_ENABLE_IMAGE_CACHE_TRACING" ENV_QTC_ENABLE_IMAGE_CACHE_TRACING OFF) +option(ENABLE_IMAGE_CACHE_TRACING "Enable image cache tracing" ${ENV_QTC_ENABLE_IMAGE_CACHE_TRACING}) +add_feature_info("Image cache tracing" ${ENABLE_IMAGE_CACHE_TRACING} "") + add_qtc_library(QmlDesignerUtils STATIC DEPENDS @@ -93,6 +97,7 @@ extend_qtc_library(QmlDesignerCore DEPENDS Nanotrace DEFINES $<$:ENABLE_PROJECT_STORAGE_TRACING> + $<$:ENABLE_IMAGE_CACHE_TRACING> ) extend_qtc_library(QmlDesignerCore diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp index a18e051c364..4da56f18eae 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp @@ -7,18 +7,39 @@ #include "imagecachestorage.h" #include "timestampprovider.h" +#include + #include namespace QmlDesigner { +using namespace NanotraceHR::Literals; + +namespace { +using TraceFile = NanotraceHR::TraceFile; + +TraceFile traceFile{"qml_designer.json"}; + +thread_local auto eventQueueData = NanotraceHR::makeEventQueueData( + traceFile); +thread_local NanotraceHR::EventQueue eventQueue = eventQueueData.createEventQueue(); + +thread_local NanotraceHR::StringViewCategory category{"image cache"_t, + eventQueue}; +} // namespace + +NanotraceHR::StringViewCategory &imageCacheCategory() +{ + return category; +} + AsynchronousImageCache::AsynchronousImageCache(ImageCacheStorageInterface &storage, ImageCacheGeneratorInterface &generator, TimeStampProviderInterface &timeStampProvider) : m_storage(storage) , m_generator(generator) , m_timeStampProvider(timeStampProvider) -{ -} +{} AsynchronousImageCache::~AsynchronousImageCache() { @@ -31,6 +52,7 @@ void AsynchronousImageCache::request(Utils::SmallStringView name, ImageCache::CaptureImageCallback captureCallback, ImageCache::AbortCallback abortCallback, ImageCache::AuxiliaryData auxiliaryData, + ImageCacheTraceToken traceToken, ImageCacheStorageInterface &storage, ImageCacheGeneratorInterface &generator, TimeStampProviderInterface &timeStampProvider) @@ -40,6 +62,11 @@ void AsynchronousImageCache::request(Utils::SmallStringView name, const auto timeStamp = timeStampProvider.timeStamp(name); auto requestImageFromStorage = [&](RequestType requestType) { + imageCacheCategory().tickAsynchronous(traceToken, "start fetching image from storage"_t); + + QScopeGuard finally{[=] { + imageCacheCategory().tickAsynchronous(traceToken, "end fetching image from storage"_t); + }}; switch (requestType) { case RequestType::Image: return storage.fetchImage(id, timeStamp); @@ -56,14 +83,19 @@ void AsynchronousImageCache::request(Utils::SmallStringView name, const auto entry = requestImageFromStorage(requestType); if (entry) { - if (entry->isNull()) + if (entry->isNull()) { abortCallback(ImageCache::AbortReason::Failed); - else + imageCacheCategory().endAsynchronous(traceToken, + "abort image request because entry in database is null"_t); + } else { captureCallback(*entry); + imageCacheCategory().endAsynchronous(traceToken, "image request delivered from storage"_t); + } } else { auto callback = [captureCallback = std::move(captureCallback), - requestType](const QImage &image, const QImage &midSizeImage, const QImage &smallImage) { + requestType, + traceToken](const QImage &image, const QImage &midSizeImage, const QImage &smallImage) { auto selectImage = [](RequestType requestType, const QImage &image, const QImage &midSizeImage, @@ -82,7 +114,12 @@ void AsynchronousImageCache::request(Utils::SmallStringView name, return image; }; captureCallback(selectImage(requestType, image, midSizeImage, smallImage)); + imageCacheCategory().endAsynchronous(traceToken, + "image request delivered from generation"_t); }; + + imageCacheCategory().tickAsynchronous(traceToken, "request image generation"_t); + generator.generateImage(name, extraId, timeStamp, @@ -98,12 +135,15 @@ void AsynchronousImageCache::requestImage(Utils::SmallStringView name, Utils::SmallStringView extraId, ImageCache::AuxiliaryData auxiliaryData) { + auto traceToken = imageCacheCategory().beginAsynchronous( + "request image in asynchornous image cache"_t); m_taskQueue.addTask(std::move(name), std::move(extraId), std::move(captureCallback), std::move(abortCallback), std::move(auxiliaryData), - RequestType::Image); + RequestType::Image, + traceToken); } void AsynchronousImageCache::requestMidSizeImage(Utils::SmallStringView name, @@ -112,12 +152,15 @@ void AsynchronousImageCache::requestMidSizeImage(Utils::SmallStringView name, Utils::SmallStringView extraId, ImageCache::AuxiliaryData auxiliaryData) { + auto traceToken = imageCacheCategory().beginAsynchronous( + "request mid size image in asynchornous image cache"_t); m_taskQueue.addTask(std::move(name), std::move(extraId), std::move(captureCallback), std::move(abortCallback), std::move(auxiliaryData), - RequestType::MidSizeImage); + RequestType::MidSizeImage, + traceToken); } void AsynchronousImageCache::requestSmallImage(Utils::SmallStringView name, @@ -126,12 +169,15 @@ void AsynchronousImageCache::requestSmallImage(Utils::SmallStringView name, Utils::SmallStringView extraId, ImageCache::AuxiliaryData auxiliaryData) { + auto traceToken = imageCacheCategory().beginAsynchronous( + "request small size image in asynchornous image cache"_t); m_taskQueue.addTask(std::move(name), std::move(extraId), std::move(captureCallback), std::move(abortCallback), std::move(auxiliaryData), - RequestType::SmallImage); + RequestType::SmallImage, + traceToken); } void AsynchronousImageCache::clean() diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h index 3eed4a4487c..fc03cccce8e 100644 --- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h +++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h @@ -6,6 +6,7 @@ #include "asynchronousimagecacheinterface.h" #include +#include #include #include @@ -21,6 +22,19 @@ class ImageCacheStorageInterface; class ImageCacheGeneratorInterface; class ImageCacheCollectorInterface; +constexpr bool imageCacheTracingIsEnabled() +{ +#ifdef ENABLE_IMAGE_CACHE_TRACING + return NanotraceHR::isTracerActive(); +#else + return false; +#endif +} + +using ImageCacheTraceToken = NanotraceHR::Token; + +NanotraceHR::StringViewCategory &imageCacheCategory(); + class AsynchronousImageCache final : public AsynchronousImageCacheInterface { public: @@ -53,18 +67,21 @@ private: struct Entry { Entry() = default; + Entry(Utils::PathString name, Utils::SmallString extraId, ImageCache::CaptureImageCallback &&captureCallback, ImageCache::AbortCallback &&abortCallback, ImageCache::AuxiliaryData &&auxiliaryData, - RequestType requestType) + RequestType requestType, + ImageCacheTraceToken traceToken) : name{std::move(name)} , extraId{std::move(extraId)} , captureCallback{std::move(captureCallback)} , abortCallback{std::move(abortCallback)} , auxiliaryData{std::move(auxiliaryData)} , requestType{requestType} + , traceToken{traceToken} {} Utils::PathString name; @@ -73,6 +90,7 @@ private: ImageCache::AbortCallback abortCallback; ImageCache::AuxiliaryData auxiliaryData; RequestType requestType = RequestType::Image; + ImageCacheTraceToken traceToken; }; static void request(Utils::SmallStringView name, @@ -81,6 +99,7 @@ private: ImageCache::CaptureImageCallback captureCallback, ImageCache::AbortCallback abortCallback, ImageCache::AuxiliaryData auxiliaryData, + ImageCacheTraceToken traceToken, ImageCacheStorageInterface &storage, ImageCacheGeneratorInterface &generator, TimeStampProviderInterface &timeStampProvider); @@ -95,6 +114,7 @@ private: std::move(entry.captureCallback), std::move(entry.abortCallback), std::move(entry.auxiliaryData), + entry.traceToken, storage, generator, timeStampProvider); @@ -107,7 +127,13 @@ private: struct Clean { - void operator()(Entry &entry) { entry.abortCallback(ImageCache::AbortReason::Abort); } + void operator()(Entry &entry) + { + using namespace NanotraceHR::Literals; + + entry.abortCallback(ImageCache::AbortReason::Abort); + imageCacheCategory().endAsynchronous(entry.traceToken, "aborted for cleanup"_t); + } }; private: