From 935e96a3bc80895520ccb01749e24793cebcddf4 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 27 Oct 2021 14:38:46 -0400 Subject: [PATCH] [stats] add hpa_gratuitous stat #2199 --- NEWS.md | 10 ++++++++++ USAGE.md | 1 + doc/man/man3/notcurses_stats.3.md | 11 +++++++++++ include/notcurses/notcurses.h | 1 + src/lib/stats.c | 10 +++++++--- src/lib/termdesc.c | 2 +- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 3d80e3c74..832f470b6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,16 @@ rearrangements of Notcurses. `notcurses_options`, for which I make no apology. If you've been avoiding deprecated functionality, ABI3 ought require small changes, if any. +* 2.4.9 (not yet released) + * On transition between `ncplane`s (on terminals implementing complex wide + glyphs), Notcurses now always issues an `hpa` sequence to force horizontal + positioning. This fixes a number of longstanding bugs in e.g. the + `[uniblock]` and `[whiteout]` demos at the cost of some extra control + sequences. For more information, see + [issue 2199](https://github.com/dankamongmen/notcurses/issues/2199). The + number of `hpa`s issued in this manner is tracked in a new stat, + `hpa_gratuitous`. + * 2.4.8 (2021-10-23) * Added new functions `notcurses_canpixel()` and `notcurses_osversion()`. * `notcurses_get()` now evaluates its timeout against `CLOCK_MONOTONIC` diff --git a/USAGE.md b/USAGE.md index a797c83cb..9c9d3eb37 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3587,6 +3587,7 @@ typedef struct ncstats { uint64_t sprixelbytes; // sprixel bytes emitted uint64_t appsync_updates; // application-synchronized updates uint64_t input_errors; // errors processing control sequences/utf8 + uint64_t hpa_gratuitous; // unnecessary hpas issued // current state -- these can decrease uint64_t fbbytes; // total bytes devoted to all active framebuffers diff --git a/doc/man/man3/notcurses_stats.3.md b/doc/man/man3/notcurses_stats.3.md index e4e3edd3e..e2b78bb02 100644 --- a/doc/man/man3/notcurses_stats.3.md +++ b/doc/man/man3/notcurses_stats.3.md @@ -44,6 +44,7 @@ typedef struct ncstats { uint64_t appsync_updates; // application-synchronized updates uint64_t input_events; // inputs received or synthesized uint64_t input_errors; // errors processing input + uint64_t hpa_gratuitous; // gratuitous HPAs issued // current state -- these can decrease uint64_t fbbytes; // bytes devoted to framebuffers @@ -117,6 +118,15 @@ include move/delete operations, nor glyphs used to erase sprixels. **input_errors** is the number of errors while processing input, e.g. malformed control sequences or invalid UTF-8 (see **utf8(7)**). +**hpa_gratuitous** is the number of **hpa** (horizontal position absolute, +see **terminfo(5)**) control sequences issued where not strictly necessary. +This is done to cope with fundamental ambiguities regarding glyph +width. It is not generally possible to know how wide a glyph will be rendered +on a given combination of font, font rendering engine, and terminal. Indeed, it +is not even generally possible to know how many glyphs will result from a +sequence of EGCs. As a result, Notcurses sometimes issues "gratuitous" **hpa** +controls. + # NOTES Unsuccessful render operations do not contribute to the render timing stats. @@ -138,4 +148,5 @@ object on success, or **NULL** on failure. **mmap(2)**, **notcurses(3)**, **notcurses_render(3)**, +**terminfo(5)**, **utf8(7)** diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 702d6ccce..a34b4c0ca 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1541,6 +1541,7 @@ typedef struct ncstats { uint64_t sprixelbytes; // sprixel bytes emitted uint64_t input_errors; // errors processing control sequences/utf8 uint64_t input_events; // characters returned to userspace + uint64_t hpa_gratuitous; // unnecessary hpas issued } ncstats; // Allocate an ncstats object. Use this rather than allocating your own, since diff --git a/src/lib/stats.c b/src/lib/stats.c index c10cec48b..1e51f0ce6 100644 --- a/src/lib/stats.c +++ b/src/lib/stats.c @@ -152,6 +152,7 @@ void notcurses_stats_reset(notcurses* nc, ncstats* stats){ stash->appsync_updates += nc->stats.s.appsync_updates; stash->input_errors += nc->stats.s.input_errors; stash->input_events += nc->stats.s.input_events; + stash->hpa_gratuitous += nc->stats.s.hpa_gratuitous; stash->fbbytes = nc->stats.s.fbbytes; stash->planes = nc->stats.s.planes; @@ -208,18 +209,21 @@ void summarize_stats(notcurses* nc){ stats->input_events, stats->input_events == 1 ? "" : "s"); } - fprintf(stderr, "%s%"PRIu64" failed render%s, %"PRIu64" failed raster%s, %"PRIu64" refresh%s, %"PRIu64" input error%s" NL, + fprintf(stderr, "%s%"PRIu64" failed render%s, %"PRIu64" failed raster%s, %" + PRIu64" refresh%s, %"PRIu64" input error%s" NL, clreol, stats->failed_renders, stats->failed_renders == 1 ? "" : "s", stats->failed_writeouts, stats->failed_writeouts == 1 ? "" : "s", stats->refreshes, stats->refreshes == 1 ? "" : "es", stats->input_errors, stats->input_errors == 1 ? "" : "s"); - fprintf(stderr, "%sRGB emits:elides: def %"PRIu64":%"PRIu64" fg %"PRIu64":%"PRIu64" bg %"PRIu64":%"PRIu64"" NL, + fprintf(stderr, "%sRGB emits:elides: def %"PRIu64":%"PRIu64" fg %"PRIu64":%" + PRIu64" bg %"PRIu64":%"PRIu64" Ghpa: %"PRIu64 NL, clreol, stats->defaultemissions, stats->defaultelisions, stats->fgemissions, stats->fgelisions, stats->bgemissions, - stats->bgelisions); + stats->bgelisions, + stats->hpa_gratuitous); fprintf(stderr, "%sCell emits:elides: %"PRIu64":%"PRIu64" (%.2f%%) %.2f%% %.2f%% %.2f%%" NL, clreol, stats->cellemissions, stats->cellelisions, (stats->cellemissions + stats->cellelisions) == 0 ? 0 : diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c index 5f4ee138d..921652fd5 100644 --- a/src/lib/termdesc.c +++ b/src/lib/termdesc.c @@ -423,7 +423,7 @@ send_initial_queries(int fd, bool minimal, bool noaltscreen){ } } size_t len = strlen(queries); - loginfo("sending %lluB queries\n", (unsigned long long)len); + loginfo("sending %lluB\n", (unsigned long long)len); if(blocking_write(fd, queries, len)){ return -1; }