Add benchmark
This commit is contained in:
1 parent
4cc8bcbddd
commit
646001a672
7 files changed
+446
-20
No files matched your search
@@ -389,6 +389,7 @@ STR_DELETE_CONFIRM: "Delete this server?"
|
||||
STR_OPDS_SERVERS: "OPDS Servers"
|
||||
STR_AUTO_TURN_ENABLED: "Auto Turn Enabled: "
|
||||
STR_AUTO_TURN_PAGES_PER_MIN: "Auto Turn (Pages Per Minute)"
|
||||
STR_RENDER_BENCHMARK: "Render Benchmark"
|
||||
STR_WEATHER: "Weather"
|
||||
STR_WEATHER_LOCATION: "Location"
|
||||
STR_WEATHER_UNITS: "Units"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <Epub/Page.h>
|
||||
#include <Epub/blocks/TextBlock.h>
|
||||
#include <FontCacheManager.h>
|
||||
#include <FontDecompressor.h>
|
||||
#include <FsHelpers.h>
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalStorage.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "EpubReaderChapterSelectionActivity.h"
|
||||
#include "EpubReaderFootnotesActivity.h"
|
||||
#include "EpubReaderPercentSelectionActivity.h"
|
||||
#include "EpubRenderBenchmarkActivity.h"
|
||||
#include "GlobalBookmarkIndex.h"
|
||||
#include "KOReaderCredentialStore.h"
|
||||
#include "MappedInputManager.h"
|
||||
@@ -79,6 +81,20 @@ int clampPercent(int percent) {
|
||||
return percent;
|
||||
}
|
||||
|
||||
const char* orientationToString(const GfxRenderer::Orientation orientation) {
|
||||
switch (orientation) {
|
||||
case GfxRenderer::Portrait:
|
||||
return "Portrait";
|
||||
case GfxRenderer::LandscapeClockwise:
|
||||
return "Landscape CW";
|
||||
case GfxRenderer::PortraitInverted:
|
||||
return "Portrait Inverted";
|
||||
case GfxRenderer::LandscapeCounterClockwise:
|
||||
return "Landscape CCW";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void EpubReaderActivity::onEnter() {
|
||||
@@ -593,6 +609,10 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
onGoHome();
|
||||
return;
|
||||
}
|
||||
case EpubReaderMenuActivity::MenuAction::RENDER_BENCHMARK: {
|
||||
runRenderBenchmark();
|
||||
break;
|
||||
}
|
||||
case EpubReaderMenuActivity::MenuAction::SCREENSHOT: {
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
@@ -620,6 +640,202 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::runRenderBenchmark() {
|
||||
if (!epub) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!section) {
|
||||
requestUpdateAndWait();
|
||||
if (!section) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const LastRenderStats startSnapshot = lastRenderStats;
|
||||
BenchmarkAggregate aggregate;
|
||||
auto recordRender = [&aggregate](const LastRenderStats& snapshot) {
|
||||
if (!snapshot.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
aggregate.renderCount++;
|
||||
aggregate.imagePageCount += snapshot.hadImages ? 1 : 0;
|
||||
aggregate.cacheRebuildCount += snapshot.cacheRebuilt ? 1 : 0;
|
||||
if (snapshot.footnoteCount > aggregate.maxFootnotes) {
|
||||
aggregate.maxFootnotes = snapshot.footnoteCount;
|
||||
}
|
||||
|
||||
aggregate.totalRequestRenderMs += snapshot.requestRenderMs;
|
||||
if (aggregate.renderCount == 1 || snapshot.requestRenderMs < aggregate.minRequestRenderMs) {
|
||||
aggregate.minRequestRenderMs = snapshot.requestRenderMs;
|
||||
}
|
||||
if (snapshot.requestRenderMs > aggregate.maxRequestRenderMs) {
|
||||
aggregate.maxRequestRenderMs = snapshot.requestRenderMs;
|
||||
}
|
||||
|
||||
aggregate.totalRenderMs += snapshot.phases.totalMs;
|
||||
if (aggregate.renderCount == 1 || snapshot.phases.totalMs < aggregate.minRenderMs) {
|
||||
aggregate.minRenderMs = snapshot.phases.totalMs;
|
||||
}
|
||||
if (snapshot.phases.totalMs > aggregate.maxRenderMs) {
|
||||
aggregate.maxRenderMs = snapshot.phases.totalMs;
|
||||
}
|
||||
|
||||
aggregate.totalSectionLoadMs += snapshot.sectionLoadMs;
|
||||
aggregate.totalPageLoadMs += snapshot.pageLoadMs;
|
||||
aggregate.totalPhases.prewarmMs += snapshot.phases.prewarmMs;
|
||||
aggregate.totalPhases.bwRenderMs += snapshot.phases.bwRenderMs;
|
||||
aggregate.totalPhases.displayMs += snapshot.phases.displayMs;
|
||||
aggregate.totalPhases.bwStoreMs += snapshot.phases.bwStoreMs;
|
||||
aggregate.totalPhases.grayLsbMs += snapshot.phases.grayLsbMs;
|
||||
aggregate.totalPhases.grayMsbMs += snapshot.phases.grayMsbMs;
|
||||
aggregate.totalPhases.grayDisplayMs += snapshot.phases.grayDisplayMs;
|
||||
aggregate.totalPhases.bwRestoreMs += snapshot.phases.bwRestoreMs;
|
||||
aggregate.totalPhases.totalMs += snapshot.phases.totalMs;
|
||||
|
||||
aggregate.totalFontCacheHits += snapshot.fontCacheHits;
|
||||
aggregate.totalFontCacheMisses += snapshot.fontCacheMisses;
|
||||
aggregate.totalFontDecompressMs += snapshot.fontDecompressMs;
|
||||
aggregate.totalFontGetBitmapTimeUs += snapshot.fontGetBitmapTimeUs;
|
||||
aggregate.totalFontGetBitmapCalls += snapshot.fontGetBitmapCalls;
|
||||
|
||||
if (aggregate.renderCount == 1 || snapshot.freeHeapAfter < aggregate.minFreeHeapAfter) {
|
||||
aggregate.minFreeHeapAfter = snapshot.freeHeapAfter;
|
||||
}
|
||||
if (snapshot.freeHeapAfter > aggregate.maxFreeHeapAfter) {
|
||||
aggregate.maxFreeHeapAfter = snapshot.freeHeapAfter;
|
||||
}
|
||||
};
|
||||
const unsigned long startTime = millis();
|
||||
int forwardTurns = 0;
|
||||
int backwardTurns = 0;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!stepPageState(true)) {
|
||||
break;
|
||||
}
|
||||
requestUpdateAndWait();
|
||||
recordRender(lastRenderStats);
|
||||
forwardTurns++;
|
||||
}
|
||||
|
||||
const unsigned long forwardMs = millis() - startTime;
|
||||
const unsigned long backwardStart = millis();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!stepPageState(false)) {
|
||||
break;
|
||||
}
|
||||
requestUpdateAndWait();
|
||||
recordRender(lastRenderStats);
|
||||
backwardTurns++;
|
||||
}
|
||||
|
||||
const unsigned long backwardMs = millis() - backwardStart;
|
||||
|
||||
startActivityForResult(
|
||||
std::make_unique<EpubRenderBenchmarkActivity>(
|
||||
renderer, mappedInput,
|
||||
buildRenderBenchmarkReport(startSnapshot, aggregate, forwardTurns, forwardMs, backwardTurns, backwardMs)),
|
||||
[this](const ActivityResult&) { requestUpdate(); });
|
||||
}
|
||||
|
||||
std::string EpubReaderActivity::buildRenderBenchmarkReport(const LastRenderStats& startSnapshot,
|
||||
const BenchmarkAggregate& aggregate, const int forwardTurns,
|
||||
const unsigned long forwardMs, const int backwardTurns,
|
||||
const unsigned long backwardMs) const {
|
||||
const LastRenderStats& endSnapshot = lastRenderStats.valid ? lastRenderStats : startSnapshot;
|
||||
|
||||
std::string report;
|
||||
report.reserve(768);
|
||||
|
||||
auto appendLine = [&report](const std::string& line) {
|
||||
if (!report.empty()) {
|
||||
report += '\n';
|
||||
}
|
||||
report += line;
|
||||
};
|
||||
|
||||
appendLine("Forward 10: " + std::to_string(forwardTurns) + " turns in " + std::to_string(forwardMs) + " ms");
|
||||
if (forwardTurns > 0) {
|
||||
appendLine("Forward avg: " + std::to_string(forwardMs / static_cast<unsigned long>(forwardTurns)) + " ms/turn");
|
||||
}
|
||||
appendLine("Backward 10: " + std::to_string(backwardTurns) + " turns in " + std::to_string(backwardMs) + " ms");
|
||||
if (backwardTurns > 0) {
|
||||
appendLine("Backward avg: " + std::to_string(backwardMs / static_cast<unsigned long>(backwardTurns)) + " ms/turn");
|
||||
}
|
||||
appendLine("Measured renders: " + std::to_string(aggregate.renderCount) + ", image pages " +
|
||||
std::to_string(aggregate.imagePageCount) + ", cache rebuilds " +
|
||||
std::to_string(aggregate.cacheRebuildCount));
|
||||
|
||||
appendLine("Start: spine " + std::to_string(startSnapshot.spineIndex) + ", page " +
|
||||
std::to_string(startSnapshot.pageIndex + 1) + "/" + std::to_string(startSnapshot.pageCount));
|
||||
appendLine("End: spine " + std::to_string(endSnapshot.spineIndex) + ", page " +
|
||||
std::to_string(endSnapshot.pageIndex + 1) + "/" + std::to_string(endSnapshot.pageCount));
|
||||
appendLine("Orientation: " +
|
||||
std::string(orientationToString(static_cast<GfxRenderer::Orientation>(endSnapshot.orientation))));
|
||||
appendLine("Viewport: " + std::to_string(endSnapshot.viewportWidth) + "x" +
|
||||
std::to_string(endSnapshot.viewportHeight) + " px, margins T/R/B/L " +
|
||||
std::to_string(endSnapshot.marginTop) + "/" + std::to_string(endSnapshot.marginRight) + "/" +
|
||||
std::to_string(endSnapshot.marginBottom) + "/" + std::to_string(endSnapshot.marginLeft));
|
||||
appendLine("Font: " + std::to_string(endSnapshot.effectiveFontId) + ", embedded CSS " +
|
||||
std::string(endSnapshot.embeddedStyle ? "on" : "off") + ", images " +
|
||||
std::to_string(endSnapshot.imageRendering) + ", AA " +
|
||||
std::string(endSnapshot.textAntiAliasing ? "on" : "off"));
|
||||
appendLine("Last page: images " + std::string(endSnapshot.hadImages ? "yes" : "no") + ", footnotes " +
|
||||
std::to_string(endSnapshot.footnoteCount) + ", cache rebuilt " +
|
||||
std::string(endSnapshot.cacheRebuilt ? "yes" : "no"));
|
||||
if (aggregate.renderCount > 0) {
|
||||
appendLine("Render avg/min/max: request " +
|
||||
std::to_string(aggregate.totalRequestRenderMs / static_cast<unsigned long>(aggregate.renderCount)) +
|
||||
"/" + std::to_string(aggregate.minRequestRenderMs) + "/" + std::to_string(aggregate.maxRequestRenderMs) +
|
||||
" ms, core " +
|
||||
std::to_string(aggregate.totalRenderMs / static_cast<unsigned long>(aggregate.renderCount)) + "/" +
|
||||
std::to_string(aggregate.minRenderMs) + "/" + std::to_string(aggregate.maxRenderMs) + " ms");
|
||||
appendLine("Aggregate loads: section " + std::to_string(aggregate.totalSectionLoadMs) + " ms, page " +
|
||||
std::to_string(aggregate.totalPageLoadMs) + " ms, max footnotes " +
|
||||
std::to_string(aggregate.maxFootnotes));
|
||||
appendLine("Aggregate phases: prewarm " + std::to_string(aggregate.totalPhases.prewarmMs) + ", bw " +
|
||||
std::to_string(aggregate.totalPhases.bwRenderMs) + ", display " +
|
||||
std::to_string(aggregate.totalPhases.displayMs) + ", gray total " +
|
||||
std::to_string(aggregate.totalPhases.grayLsbMs + aggregate.totalPhases.grayMsbMs +
|
||||
aggregate.totalPhases.grayDisplayMs));
|
||||
appendLine("Aggregate font: hits " + std::to_string(aggregate.totalFontCacheHits) + ", misses " +
|
||||
std::to_string(aggregate.totalFontCacheMisses) + ", decompress " +
|
||||
std::to_string(aggregate.totalFontDecompressMs) + " ms");
|
||||
appendLine("Aggregate glyph lookups: " + std::to_string(aggregate.totalFontGetBitmapCalls) + " calls, " +
|
||||
std::to_string(aggregate.totalFontGetBitmapTimeUs) + " us total");
|
||||
appendLine("Heap after render min/max: " + std::to_string(aggregate.minFreeHeapAfter) + "/" +
|
||||
std::to_string(aggregate.maxFreeHeapAfter));
|
||||
}
|
||||
appendLine("Last render: request " + std::to_string(endSnapshot.requestRenderMs) + " ms, section load " +
|
||||
std::to_string(endSnapshot.sectionLoadMs) + " ms, page load " + std::to_string(endSnapshot.pageLoadMs) +
|
||||
" ms, render total " + std::to_string(endSnapshot.phases.totalMs) + " ms");
|
||||
appendLine("Phases: prewarm " + std::to_string(endSnapshot.phases.prewarmMs) + ", bw " +
|
||||
std::to_string(endSnapshot.phases.bwRenderMs) + ", display " +
|
||||
std::to_string(endSnapshot.phases.displayMs) + ", store " + std::to_string(endSnapshot.phases.bwStoreMs) +
|
||||
", gray lsb " + std::to_string(endSnapshot.phases.grayLsbMs) + ", gray msb " +
|
||||
std::to_string(endSnapshot.phases.grayMsbMs) + ", gray display " +
|
||||
std::to_string(endSnapshot.phases.grayDisplayMs) + ", restore " +
|
||||
std::to_string(endSnapshot.phases.bwRestoreMs));
|
||||
appendLine("Font cache: hits " + std::to_string(endSnapshot.fontCacheHits) + ", misses " +
|
||||
std::to_string(endSnapshot.fontCacheMisses) + ", decompress " +
|
||||
std::to_string(endSnapshot.fontDecompressMs) + " ms, groups " +
|
||||
std::to_string(endSnapshot.fontUniqueGroups));
|
||||
appendLine("Font buffers: page " + std::to_string(endSnapshot.fontPageBufferBytes) + ", glyph table " +
|
||||
std::to_string(endSnapshot.fontPageGlyphsBytes) + ", hot group " +
|
||||
std::to_string(endSnapshot.fontHotGroupBytes) + ", peak temp " +
|
||||
std::to_string(endSnapshot.fontPeakTempBytes));
|
||||
appendLine("Glyph lookups: " + std::to_string(endSnapshot.fontGetBitmapCalls) + " calls, " +
|
||||
std::to_string(endSnapshot.fontGetBitmapTimeUs) + " us total");
|
||||
appendLine("Heap: before " + std::to_string(endSnapshot.freeHeapBefore) + "/" +
|
||||
std::to_string(endSnapshot.largestFreeBlockBefore) + ", after " +
|
||||
std::to_string(endSnapshot.freeHeapAfter) + "/" + std::to_string(endSnapshot.largestFreeBlockAfter));
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
void EpubReaderActivity::launchKOReaderSync(const SyncLaunchMode mode) {
|
||||
if (!epub) {
|
||||
return;
|
||||
@@ -903,33 +1119,43 @@ int EpubReaderActivity::getEffectiveReaderFontId() const {
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::pageTurn(bool isForwardTurn) {
|
||||
bool EpubReaderActivity::stepPageState(const bool isForwardTurn) {
|
||||
if (!epub || !section || section->pageCount <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isForwardTurn) {
|
||||
if (section->currentPage < section->pageCount - 1) {
|
||||
section->currentPage++;
|
||||
} else if (currentSpineIndex + 1 < epub->getSpineItemsCount()) {
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex++;
|
||||
section.reset();
|
||||
} else {
|
||||
// We don't want to delete the section mid-render, so grab the semaphore
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex++;
|
||||
section.reset();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (section->currentPage > 0) {
|
||||
section->currentPage--;
|
||||
} else if (currentSpineIndex > 0) {
|
||||
// We don't want to delete the section mid-render, so grab the semaphore
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = UINT16_MAX;
|
||||
currentSpineIndex--;
|
||||
section.reset();
|
||||
}
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = UINT16_MAX;
|
||||
currentSpineIndex--;
|
||||
section.reset();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
lastPageTurnTime = millis();
|
||||
return true;
|
||||
}
|
||||
|
||||
void EpubReaderActivity::pageTurn(bool isForwardTurn) {
|
||||
if (!stepPageState(isForwardTurn)) {
|
||||
return;
|
||||
}
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
@@ -979,18 +1205,34 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
|
||||
const uint16_t viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
||||
const uint16_t viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom;
|
||||
lastRenderStats = {};
|
||||
lastRenderStats.orientation = static_cast<uint8_t>(renderer.getOrientation());
|
||||
lastRenderStats.marginTop = orientedMarginTop;
|
||||
lastRenderStats.marginRight = orientedMarginRight;
|
||||
lastRenderStats.marginBottom = orientedMarginBottom;
|
||||
lastRenderStats.marginLeft = orientedMarginLeft;
|
||||
lastRenderStats.viewportWidth = viewportWidth;
|
||||
lastRenderStats.viewportHeight = viewportHeight;
|
||||
lastRenderStats.embeddedStyle = getEffectiveEmbeddedStyle();
|
||||
lastRenderStats.imageRendering = getEffectiveImageRendering();
|
||||
lastRenderStats.effectiveFontId = getEffectiveReaderFontId();
|
||||
lastRenderStats.textAntiAliasing = SETTINGS.textAntiAliasing;
|
||||
lastRenderStats.freeHeapBefore = esp_get_free_heap_size();
|
||||
lastRenderStats.largestFreeBlockBefore = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
|
||||
|
||||
if (!section) {
|
||||
const bool embeddedStyle = getEffectiveEmbeddedStyle();
|
||||
const uint8_t imageRendering = getEffectiveImageRendering();
|
||||
const bool embeddedStyle = lastRenderStats.embeddedStyle;
|
||||
const uint8_t imageRendering = lastRenderStats.imageRendering;
|
||||
const auto filepath = epub->getSpineItem(currentSpineIndex).href;
|
||||
LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex);
|
||||
section = std::make_unique<Section>(epub, currentSpineIndex, renderer);
|
||||
const unsigned long sectionStart = millis();
|
||||
|
||||
if (!section->loadSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
LOG_DBG("ERS", "Cache not found, building...");
|
||||
lastRenderStats.cacheRebuilt = true;
|
||||
|
||||
Rect popupRect{};
|
||||
const auto progressFn = [this, &popupRect](int progress) {
|
||||
@@ -1011,6 +1253,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
} else {
|
||||
LOG_DBG("ERS", "Cache found, skipping build...");
|
||||
}
|
||||
lastRenderStats.sectionLoadMs = millis() - sectionStart;
|
||||
|
||||
if (nextPageNumber == UINT16_MAX) {
|
||||
section->currentPage = section->pageCount - 1;
|
||||
@@ -1097,7 +1340,9 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned long pageLoadStart = millis();
|
||||
auto p = section->loadPageFromSectionFile();
|
||||
lastRenderStats.pageLoadMs = millis() - pageLoadStart;
|
||||
if (!p) {
|
||||
LOG_ERR("ERS", "Failed to load page from SD - clearing section cache");
|
||||
section->clearCache();
|
||||
@@ -1110,13 +1355,22 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
|
||||
// Collect footnotes from the loaded page
|
||||
currentPageFootnotes = std::move(p->footnotes);
|
||||
lastRenderStats.hadImages = p->hasImages();
|
||||
lastRenderStats.footnoteCount = static_cast<int>(currentPageFootnotes.size());
|
||||
lastRenderStats.spineIndex = currentSpineIndex;
|
||||
lastRenderStats.pageIndex = section->currentPage;
|
||||
lastRenderStats.pageCount = section->pageCount;
|
||||
|
||||
const auto start = millis();
|
||||
renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
||||
LOG_DBG("ERS", "Rendered page in %dms", millis() - start);
|
||||
lastRenderStats.requestRenderMs = millis() - start;
|
||||
LOG_DBG("ERS", "Rendered page in %dms", lastRenderStats.requestRenderMs);
|
||||
}
|
||||
silentIndexNextChapterIfNeeded(viewportWidth, viewportHeight);
|
||||
saveProgress(currentSpineIndex, section->currentPage, section->pageCount);
|
||||
lastRenderStats.freeHeapAfter = esp_get_free_heap_size();
|
||||
lastRenderStats.largestFreeBlockAfter = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
|
||||
lastRenderStats.valid = true;
|
||||
|
||||
if (pendingScreenshot) {
|
||||
pendingScreenshot = false;
|
||||
@@ -1200,6 +1454,8 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
bool imagePageWithAA = page->hasImages() && SETTINGS.textAntiAliasing;
|
||||
bool forceHalfRefreshThisPage = pendingHalfRefreshAfterImagePage && SETTINGS.halfRefreshAfterImagePage;
|
||||
pendingHalfRefreshAfterImagePage = false;
|
||||
lastRenderStats.imagePageWithAA = imagePageWithAA;
|
||||
lastRenderStats.forcedHalfRefresh = forceHalfRefreshThisPage;
|
||||
|
||||
logReaderMemSnapshot("before_bw_render");
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
@@ -1283,6 +1539,10 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
logReaderMemSnapshot("bw_restore_end");
|
||||
|
||||
const auto tEnd = millis();
|
||||
lastRenderStats.usedGrayscale = true;
|
||||
lastRenderStats.phases = {tPrewarm - t0, tBwRender - tPrewarm, tDisplay - tBwRender,
|
||||
tBwStore - tDisplay, tGrayLsb - tBwStore, tGrayMsb - tGrayLsb,
|
||||
tGrayDisplay - tGrayMsb, tBwRestore - tGrayDisplay, tEnd - t0};
|
||||
LOG_DBG("ERS",
|
||||
"Page render: prewarm=%lums bw_render=%lums display=%lums bw_store=%lums "
|
||||
"gray_lsb=%lums gray_msb=%lums gray_display=%lums bw_restore=%lums total=%lums",
|
||||
@@ -1296,11 +1556,31 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
logReaderMemSnapshot("bw_restore_end");
|
||||
|
||||
const auto tEnd = millis();
|
||||
lastRenderStats.usedGrayscale = false;
|
||||
lastRenderStats.phases = {
|
||||
tPrewarm - t0, tBwRender - tPrewarm, tDisplay - tBwRender, tBwStore - tDisplay, 0, 0, 0, tBwRestore - tBwStore,
|
||||
tEnd - t0};
|
||||
LOG_DBG("ERS",
|
||||
"Page render: prewarm=%lums bw_render=%lums display=%lums bw_store=%lums bw_restore=%lums total=%lums",
|
||||
tPrewarm - t0, tBwRender - tPrewarm, tDisplay - tBwRender, tBwStore - tDisplay, tBwRestore - tBwStore,
|
||||
tEnd - t0);
|
||||
}
|
||||
|
||||
if (auto* cacheManager = renderer.getFontCacheManager()) {
|
||||
if (auto* decompressor = cacheManager->getDecompressor()) {
|
||||
const auto& stats = decompressor->getStats();
|
||||
lastRenderStats.fontCacheHits = stats.cacheHits;
|
||||
lastRenderStats.fontCacheMisses = stats.cacheMisses;
|
||||
lastRenderStats.fontDecompressMs = stats.decompressTimeMs;
|
||||
lastRenderStats.fontUniqueGroups = stats.uniqueGroupsAccessed;
|
||||
lastRenderStats.fontPageBufferBytes = stats.pageBufferBytes;
|
||||
lastRenderStats.fontPageGlyphsBytes = stats.pageGlyphsBytes;
|
||||
lastRenderStats.fontHotGroupBytes = stats.hotGroupBytes;
|
||||
lastRenderStats.fontPeakTempBytes = stats.peakTempBytes;
|
||||
lastRenderStats.fontGetBitmapTimeUs = stats.getBitmapTimeUs;
|
||||
lastRenderStats.fontGetBitmapCalls = stats.getBitmapCalls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::renderStatusBar() const {
|
||||
|
||||
@@ -38,6 +38,81 @@ class EpubReaderActivity final : public Activity {
|
||||
unsigned long lastPageTurnTime = 0UL;
|
||||
unsigned long pageTurnDuration = 0UL;
|
||||
bool pendingHalfRefreshAfterImagePage = false;
|
||||
struct RenderPhaseStats {
|
||||
unsigned long prewarmMs = 0UL;
|
||||
unsigned long bwRenderMs = 0UL;
|
||||
unsigned long displayMs = 0UL;
|
||||
unsigned long bwStoreMs = 0UL;
|
||||
unsigned long grayLsbMs = 0UL;
|
||||
unsigned long grayMsbMs = 0UL;
|
||||
unsigned long grayDisplayMs = 0UL;
|
||||
unsigned long bwRestoreMs = 0UL;
|
||||
unsigned long totalMs = 0UL;
|
||||
};
|
||||
struct LastRenderStats {
|
||||
bool valid = false;
|
||||
bool cacheRebuilt = false;
|
||||
bool usedGrayscale = false;
|
||||
bool hadImages = false;
|
||||
bool imagePageWithAA = false;
|
||||
bool forcedHalfRefresh = false;
|
||||
uint8_t orientation = 0;
|
||||
uint8_t imageRendering = 0;
|
||||
bool embeddedStyle = false;
|
||||
bool textAntiAliasing = false;
|
||||
int effectiveFontId = 0;
|
||||
int spineIndex = 0;
|
||||
int pageIndex = 0;
|
||||
int pageCount = 0;
|
||||
int footnoteCount = 0;
|
||||
int marginTop = 0;
|
||||
int marginRight = 0;
|
||||
int marginBottom = 0;
|
||||
int marginLeft = 0;
|
||||
uint16_t viewportWidth = 0;
|
||||
uint16_t viewportHeight = 0;
|
||||
unsigned long sectionLoadMs = 0UL;
|
||||
unsigned long pageLoadMs = 0UL;
|
||||
unsigned long requestRenderMs = 0UL;
|
||||
RenderPhaseStats phases;
|
||||
uint32_t freeHeapBefore = 0;
|
||||
uint32_t largestFreeBlockBefore = 0;
|
||||
uint32_t freeHeapAfter = 0;
|
||||
uint32_t largestFreeBlockAfter = 0;
|
||||
uint32_t fontCacheHits = 0;
|
||||
uint32_t fontCacheMisses = 0;
|
||||
uint32_t fontDecompressMs = 0;
|
||||
uint16_t fontUniqueGroups = 0;
|
||||
uint32_t fontPageBufferBytes = 0;
|
||||
uint32_t fontPageGlyphsBytes = 0;
|
||||
uint32_t fontHotGroupBytes = 0;
|
||||
uint32_t fontPeakTempBytes = 0;
|
||||
uint32_t fontGetBitmapTimeUs = 0;
|
||||
uint32_t fontGetBitmapCalls = 0;
|
||||
};
|
||||
struct BenchmarkAggregate {
|
||||
int renderCount = 0;
|
||||
int imagePageCount = 0;
|
||||
int cacheRebuildCount = 0;
|
||||
int maxFootnotes = 0;
|
||||
unsigned long totalRequestRenderMs = 0UL;
|
||||
unsigned long minRequestRenderMs = 0UL;
|
||||
unsigned long maxRequestRenderMs = 0UL;
|
||||
unsigned long totalRenderMs = 0UL;
|
||||
unsigned long minRenderMs = 0UL;
|
||||
unsigned long maxRenderMs = 0UL;
|
||||
unsigned long totalSectionLoadMs = 0UL;
|
||||
unsigned long totalPageLoadMs = 0UL;
|
||||
RenderPhaseStats totalPhases;
|
||||
uint32_t totalFontCacheHits = 0;
|
||||
uint32_t totalFontCacheMisses = 0;
|
||||
uint32_t totalFontDecompressMs = 0;
|
||||
uint32_t totalFontGetBitmapTimeUs = 0;
|
||||
uint32_t totalFontGetBitmapCalls = 0;
|
||||
uint32_t minFreeHeapAfter = 0;
|
||||
uint32_t maxFreeHeapAfter = 0;
|
||||
};
|
||||
LastRenderStats lastRenderStats;
|
||||
// Signals that the next render should reposition within the newly loaded section
|
||||
// based on a cross-book percentage jump.
|
||||
bool pendingPercentJump = false;
|
||||
@@ -95,7 +170,12 @@ class EpubReaderActivity final : public Activity {
|
||||
bool getEffectiveEmbeddedStyle() const;
|
||||
uint8_t getEffectiveImageRendering() const;
|
||||
int getEffectiveReaderFontId() const;
|
||||
bool stepPageState(bool isForwardTurn);
|
||||
void pageTurn(bool isForwardTurn);
|
||||
void runRenderBenchmark();
|
||||
std::string buildRenderBenchmarkReport(const LastRenderStats& startSnapshot, const BenchmarkAggregate& aggregate,
|
||||
int forwardTurns, unsigned long forwardMs, int backwardTurns,
|
||||
unsigned long backwardMs) const;
|
||||
|
||||
// Footnote navigation
|
||||
void navigateToHref(const std::string& href, bool savePosition = false);
|
||||
|
||||
@@ -33,7 +33,7 @@ EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInpu
|
||||
}
|
||||
|
||||
void EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes, bool hasStarredPages) {
|
||||
menuItems.reserve(19);
|
||||
menuItems.reserve(20);
|
||||
|
||||
// --- Navigation ---
|
||||
menuItems.push_back(SettingInfo::Separator(StrId::STR_READER_NAVIGATION));
|
||||
@@ -161,6 +161,8 @@ void EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes, bool hasStarredPa
|
||||
menuItems.push_back(
|
||||
SettingInfo::Action(StrId::STR_DELETE_CACHE, SettingAction::None).withSubmenu(StrId::STR_READER_TOOLS));
|
||||
menuItems.push_back(SettingInfo::Action(StrId::STR_GO_HOME_BUTTON, SettingAction::None));
|
||||
menuItems.push_back(
|
||||
SettingInfo::Action(StrId::STR_RENDER_BENCHMARK, SettingAction::None).withSubmenu(StrId::STR_READER_TOOLS));
|
||||
}
|
||||
|
||||
EpubReaderMenuActivity::MenuAction EpubReaderMenuActivity::actionForNameId(StrId nameId) {
|
||||
@@ -195,6 +197,8 @@ EpubReaderMenuActivity::MenuAction EpubReaderMenuActivity::actionForNameId(StrId
|
||||
return MenuAction::DISPLAY_QR;
|
||||
case StrId::STR_DELETE_CACHE:
|
||||
return MenuAction::DELETE_CACHE;
|
||||
case StrId::STR_RENDER_BENCHMARK:
|
||||
return MenuAction::RENDER_BENCHMARK;
|
||||
case StrId::STR_GO_HOME_BUTTON:
|
||||
return MenuAction::GO_HOME;
|
||||
default:
|
||||
|
||||
@@ -28,7 +28,8 @@ class EpubReaderMenuActivity final : public MenuListActivity {
|
||||
PUSH_LOCAL,
|
||||
STARRED_PAGES,
|
||||
STAR_PAGE,
|
||||
DELETE_CACHE
|
||||
DELETE_CACHE,
|
||||
RENDER_BENCHMARK
|
||||
};
|
||||
|
||||
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "EpubRenderBenchmarkActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
void EpubRenderBenchmarkActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void EpubRenderBenchmarkActivity::loop() {
|
||||
if (mappedInput.wasAnyPressed() || mappedInput.wasAnyReleased()) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
void EpubRenderBenchmarkActivity::render(RenderLock&&) {
|
||||
renderer.clearScreen();
|
||||
|
||||
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
|
||||
const int titleY = contentRect.y + 12;
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, titleY, "Render Benchmark", true, EpdFontFamily::BOLD);
|
||||
|
||||
const int lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
|
||||
const int textTop = titleY + renderer.getLineHeight(UI_12_FONT_ID) + 14;
|
||||
const int textWidth = contentRect.width - 20;
|
||||
const auto lines = renderer.wrappedText(UI_10_FONT_ID, report.c_str(), textWidth, 48);
|
||||
|
||||
int y = textTop;
|
||||
for (const auto& line : lines) {
|
||||
if (y + lineHeight > contentRect.y + contentRect.height - 30) {
|
||||
break;
|
||||
}
|
||||
renderer.drawText(UI_10_FONT_ID, contentRect.x + 10, y, line.c_str(), true);
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, contentRect.y + contentRect.height - 18, "Press any button to close");
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "activities/Activity.h"
|
||||
|
||||
class EpubRenderBenchmarkActivity final : public Activity {
|
||||
public:
|
||||
explicit EpubRenderBenchmarkActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string report)
|
||||
: Activity("EpubRenderBenchmark", renderer, mappedInput), report(std::move(report)) {}
|
||||
|
||||
void onEnter() override;
|
||||
void loop() override;
|
||||
void render(RenderLock&&) override;
|
||||
|
||||
private:
|
||||
std::string report;
|
||||
};
|
||||
Reference in new issue
Block a user