add raster timing stats #1324

This commit is contained in:
nick black 2021-02-02 21:59:29 -05:00
parent d47337c4ae
commit 43dd0440f7
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
5 changed files with 54 additions and 24 deletions

View File

@ -3018,9 +3018,12 @@ typedef struct ncstats {
uint64_t render_bytes; // bytes emitted to ttyfp uint64_t render_bytes; // bytes emitted to ttyfp
int64_t render_max_bytes; // max bytes emitted for a frame int64_t render_max_bytes; // max bytes emitted for a frame
int64_t render_min_bytes; // min bytes emitted for a frame int64_t render_min_bytes; // min bytes emitted for a frame
uint64_t render_ns; // nanoseconds spent in render+raster uint64_t render_ns; // nanoseconds spent rendering
int64_t render_max_ns; // max ns spent in render+raster for a frame int64_t render_max_ns; // max ns spent in render+raster for a frame
int64_t render_min_ns; // min ns spent in render+raster for a frame int64_t render_min_ns; // min ns spent in render+raster for a frame
uint64_t raster_ns; // nanoseconds spent rasterizing
int64_t raster_max_ns; // max ns spent in raster for a frame
int64_t raster_min_ns; // min ns spent in raster for a frame
uint64_t writeout_ns; // nanoseconds spent writing frames to terminal uint64_t writeout_ns; // nanoseconds spent writing frames to terminal
int64_t writeout_max_ns; // max ns spent writing out a frame int64_t writeout_max_ns; // max ns spent writing out a frame
int64_t writeout_min_ns; // min ns spent writing out a frame int64_t writeout_min_ns; // min ns spent writing out a frame

View File

@ -20,9 +20,12 @@ typedef struct ncstats {
uint64_t render_bytes; // bytes emitted to ttyfp uint64_t render_bytes; // bytes emitted to ttyfp
int64_t render_max_bytes; // max bytes emitted for a frame int64_t render_max_bytes; // max bytes emitted for a frame
int64_t render_min_bytes; // min bytes emitted for a frame int64_t render_min_bytes; // min bytes emitted for a frame
uint64_t render_ns; // nanoseconds spent in render+raster uint64_t render_ns; // nanoseconds spent rendering
int64_t render_max_ns; // max ns spent for a frame int64_t render_max_ns; // max ns spent for a frame
int64_t render_min_ns; // min ns spent for a frame int64_t render_min_ns; // min ns spent for a frame
uint64_t raster_ns; // nanoseconds spent rasterizing
int64_t raster_max_ns; // max ns spent in raster for a frame
int64_t raster_min_ns; // min ns spent in raster for a frame
uint64_t writeout_ns; // ns spent writing frames to terminal uint64_t writeout_ns; // ns spent writing frames to terminal
int64_t writeout_max_ns; // max ns spent writing out a frame int64_t writeout_max_ns; // max ns spent writing out a frame
int64_t writeout_min_ns; // min ns spent writing out a frame int64_t writeout_min_ns; // min ns spent writing out a frame
@ -73,15 +76,19 @@ existing terminal state. As a first approximation, the time a terminal takes to
ingest and reflect a frame is dependent on the size of the rasterized frame. ingest and reflect a frame is dependent on the size of the rasterized frame.
**render_ns**, **render_max_ns**, and **render_min_ns** track the total **render_ns**, **render_max_ns**, and **render_min_ns** track the total
amount of time spent rendering and rasterizing frames in nanoseconds. Rendering amount of time spent rendering frames in nanoseconds. Rendering
and rasterizing takes place in **notcurses_render(3)**, and is the entirety of takes place in **ncpile_render** (called by **notcurses_render(3)** and
**notcurses_render_to_buffer(3)**. These steps are independent of the terminal. **notcurses_render_to_buffer**). This step is independent of the terminal.
**raster_ns**, **raster_max_ns**, and **raster_min_ns** track the total
amount of time spent rasterizing frames in nanoseconds. Rasterizing
takes place in **ncpile_raster** (called by **notcurses_raster(3)** and
**notcurses_render_to_buffer**). This step depends on the terminal definitions.
The same frame might not rasterize to the same bytes for different terminals.
**writeout_ns**, **writeout_max_ns**, and **writeout_min_ns** track the total **writeout_ns**, **writeout_max_ns**, and **writeout_min_ns** track the total
amount of time spent writing frames to the terminal. This takes place in only amount of time spent writing frames to the terminal. This takes place in
**notcurses_render(3)**. If **notcurses_render_to_buffer(3)** is used, the **ncpile_rasterize** (called by **notcurses_render(3)**).
user is responsible for writing out the frame, and it will not be tracked by
any stat.
**cellemissions** reflects the number of EGCs written to the terminal. **cellemissions** reflects the number of EGCs written to the terminal.
**cellelisions** reflects the number of cells which were not written, due to **cellelisions** reflects the number of cells which were not written, due to

View File

@ -620,7 +620,7 @@ typedef struct nccell {
uint64_t channels; // + 8B == 16B uint64_t channels; // + 8B == 16B
} nccell; } nccell;
typedef nccell cell; // FIXME backwards-compat, remove in 3.0 typedef nccell cell; // FIXME backwards-compat, remove in ABI3
#define CELL_TRIVIAL_INITIALIZER { .gcluster = 0, .gcluster_backstop = 0, .width = 0, .stylemask = 0, .channels = 0, } #define CELL_TRIVIAL_INITIALIZER { .gcluster = 0, .gcluster_backstop = 0, .width = 0, .stylemask = 0, .channels = 0, }
// do *not* load invalid EGCs using these macros! there is no way for us to // do *not* load invalid EGCs using these macros! there is no way for us to
@ -1137,8 +1137,8 @@ API struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nop
// be the top, bottom, and root of this new pile. // be the top, bottom, and root of this new pile.
API struct ncplane* ncpile_create(struct notcurses* nc, const ncplane_options* nopts); API struct ncplane* ncpile_create(struct notcurses* nc, const ncplane_options* nopts);
// This function will be removed in 3.0 in favor of ncplane_create(). // This function will be removed in ABI3 in favor of ncplane_create().
// It persists in 2.0 only for backwards compatibility. // It persists in ABI2 only for backwards compatibility.
API struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols, int y, int x, void* opaque, const char* name) API struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols, int y, int x, void* opaque, const char* name)
__attribute__ ((deprecated)); __attribute__ ((deprecated));
@ -1237,12 +1237,13 @@ typedef struct ncstats {
uint64_t writeouts; // successful ncpile_rasterize() runs uint64_t writeouts; // successful ncpile_rasterize() runs
uint64_t failed_renders; // aborted renders, should be 0 uint64_t failed_renders; // aborted renders, should be 0
uint64_t failed_writeouts; // aborted writes uint64_t failed_writeouts; // aborted writes
// FIXME these next three all ought be "writeout" or "raster"
uint64_t render_bytes; // bytes emitted to ttyfp uint64_t render_bytes; // bytes emitted to ttyfp
int64_t render_max_bytes; // max bytes emitted for a frame int64_t render_max_bytes; // max bytes emitted for a frame
int64_t render_min_bytes; // min bytes emitted for a frame int64_t render_min_bytes; // min bytes emitted for a frame
uint64_t render_ns; // nanoseconds spent in render+raster uint64_t render_ns; // nanoseconds spent rendering
int64_t render_max_ns; // max ns spent in render+raster for a frame int64_t render_max_ns; // max ns spent in render for a frame
int64_t render_min_ns; // min ns spent in render+raster for a frame int64_t render_min_ns; // min ns spent in render for a frame
uint64_t writeout_ns; // nanoseconds spent writing frames to terminal uint64_t writeout_ns; // nanoseconds spent writing frames to terminal
int64_t writeout_max_ns; // max ns spent writing out a frame int64_t writeout_max_ns; // max ns spent writing out a frame
int64_t writeout_min_ns; // min ns spent writing out a frame int64_t writeout_min_ns; // min ns spent writing out a frame
@ -1259,6 +1260,11 @@ typedef struct ncstats {
// current state -- these can decrease // current state -- these can decrease
uint64_t fbbytes; // total bytes devoted to all active framebuffers uint64_t fbbytes; // total bytes devoted to all active framebuffers
unsigned planes; // number of planes currently in existence unsigned planes; // number of planes currently in existence
// FIXME placed here for ABI compatibility; move up for ABI3
uint64_t raster_ns; // nanoseconds spent rasterizing
int64_t raster_max_ns; // max ns spent in raster for a frame
int64_t raster_min_ns; // min ns spent in raster for a frame
} ncstats; } ncstats;
// Allocate an ncstats object. Use this rather than allocating your own, since // Allocate an ncstats object. Use this rather than allocating your own, since

View File

@ -412,20 +412,18 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide
table_segment(nc, " runtime", ""); table_segment(nc, " runtime", "");
table_segment(nc, " frames", ""); table_segment(nc, " frames", "");
table_segment(nc, "output(B)", ""); table_segment(nc, "output(B)", "");
table_segment(nc, "rendering", "");
table_segment(nc, " FPS", ""); table_segment(nc, " FPS", "");
table_segment(nc, "%r", ""); table_segment(nc, "%r", "");
table_segment(nc, "%a", "");
table_segment(nc, "%w", ""); table_segment(nc, "%w", "");
table_segment(nc, "TheoFPS", "\n══╤════════╤════════╪═══════╪═════════╪════════════════╪══╪══╪═══════╣\n"); table_segment(nc, "TheoFPS", "\n══╤════════╤════════╪═══════╪═════════╪═══════╪══╪══╪══╪═══════╣\n");
char timebuf[PREFIXSTRLEN + 1]; char timebuf[PREFIXSTRLEN + 1];
char tfpsbuf[PREFIXSTRLEN + 1]; char tfpsbuf[PREFIXSTRLEN + 1];
char totalbuf[BPREFIXSTRLEN + 1]; char totalbuf[BPREFIXSTRLEN + 1];
char rtimebuf[PREFIXSTRLEN + 1];
uint64_t nsdelta = 0; uint64_t nsdelta = 0;
for(size_t i = 0 ; i < strlen(spec) ; ++i){ for(size_t i = 0 ; i < strlen(spec) ; ++i){
nsdelta += results[i].timens; nsdelta += results[i].timens;
qprefix(results[i].timens, NANOSECS_IN_SEC, timebuf, 0); qprefix(results[i].timens, NANOSECS_IN_SEC, timebuf, 0);
qprefix(results[i].stats.render_ns, NANOSECS_IN_SEC, rtimebuf, 0);
bprefix(results[i].stats.render_bytes, 1, totalbuf, 0); bprefix(results[i].stats.render_bytes, 1, totalbuf, 0);
if(results[i].stats.renders){ if(results[i].stats.renders){
qprefix((uintmax_t)results[i].stats.renders * NANOSECS_IN_SEC * 1000 / qprefix((uintmax_t)results[i].stats.renders * NANOSECS_IN_SEC * 1000 /
@ -451,13 +449,15 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide
ncdirect_set_fg_rgb(nc, rescolor); ncdirect_set_fg_rgb(nc, rescolor);
printf("%8s", demos[results[i].selector - 'a'].name); printf("%8s", demos[results[i].selector - 'a'].name);
ncdirect_set_fg_rgb8(nc, 178, 102, 255); ncdirect_set_fg_rgb8(nc, 178, 102, 255);
printf("│%*ss│%7ju│%*s│ %*ss│%7.1f│%2jd│%2jd│%*s║", printf("│%*ss│%7ju│%*s│%7.1f│%2jd│%2jd│%2jd│%*s║",
PREFIXFMT(timebuf), (uintmax_t)(results[i].stats.renders), PREFIXFMT(timebuf), (uintmax_t)(results[i].stats.renders),
BPREFIXFMT(totalbuf), PREFIXFMT(rtimebuf), BPREFIXFMT(totalbuf),
results[i].timens ? results[i].timens ?
results[i].stats.renders / ((double)results[i].timens / NANOSECS_IN_SEC) : 0.0, results[i].stats.renders / ((double)results[i].timens / NANOSECS_IN_SEC) : 0.0,
(uintmax_t)(results[i].timens ? (uintmax_t)(results[i].timens ?
results[i].stats.render_ns * 100 / results[i].timens : 0), results[i].stats.render_ns * 100 / results[i].timens : 0),
(uintmax_t)(results[i].timens ?
results[i].stats.raster_ns * 100 / results[i].timens : 0),
(uintmax_t)(results[i].timens ? (uintmax_t)(results[i].timens ?
results[i].stats.writeout_ns * 100 / results[i].timens : 0), results[i].stats.writeout_ns * 100 / results[i].timens : 0),
PREFIXFMT(tfpsbuf)); PREFIXFMT(tfpsbuf));
@ -475,13 +475,13 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide
} }
qprefix(nsdelta, NANOSECS_IN_SEC, timebuf, 0); qprefix(nsdelta, NANOSECS_IN_SEC, timebuf, 0);
bprefix(totalbytes, 1, totalbuf, 0); bprefix(totalbytes, 1, totalbuf, 0);
qprefix(totalrenderns, NANOSECS_IN_SEC, rtimebuf, 0); //qprefix(totalrenderns, NANOSECS_IN_SEC, rtimebuf, 0);
table_segment(nc, "", "══╧════════╧════════╪═══════╪═════════╪═════════╪═══════╪══╧══╧═══════╝\n"); table_segment(nc, "", "══╧════════╧════════╪═══════╪═════════╪═══════╪══╧══╧══╧═══════╝\n");
printf(" "); printf(" ");
table_printf(nc, "", "%*ss", PREFIXFMT(timebuf)); table_printf(nc, "", "%*ss", PREFIXFMT(timebuf));
table_printf(nc, "", "%7lu", totalframes); table_printf(nc, "", "%7lu", totalframes);
table_printf(nc, "", "%*s", BPREFIXFMT(totalbuf)); table_printf(nc, "", "%*s", BPREFIXFMT(totalbuf));
table_printf(nc, "", " %*ss", PREFIXFMT(rtimebuf)); //table_printf(nc, "│", " %*ss", PREFIXFMT(rtimebuf));
table_printf(nc, "", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / NANOSECS_IN_SEC) : 0); table_printf(nc, "", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / NANOSECS_IN_SEC) : 0);
printf("\n"); printf("\n");
ncdirect_set_fg_rgb8(nc, 0xff, 0xb0, 0xb0); ncdirect_set_fg_rgb8(nc, 0xff, 0xb0, 0xb0);

View File

@ -712,6 +712,7 @@ static void
stash_stats(notcurses* nc){ stash_stats(notcurses* nc){
nc->stashstats.renders += nc->stats.renders; nc->stashstats.renders += nc->stats.renders;
nc->stashstats.render_ns += nc->stats.render_ns; nc->stashstats.render_ns += nc->stats.render_ns;
nc->stashstats.raster_ns += nc->stats.raster_ns;
nc->stashstats.writeouts += nc->stats.writeouts; nc->stashstats.writeouts += nc->stats.writeouts;
nc->stashstats.writeout_ns += nc->stats.writeout_ns; nc->stashstats.writeout_ns += nc->stats.writeout_ns;
nc->stashstats.failed_renders += nc->stats.failed_renders; nc->stashstats.failed_renders += nc->stats.failed_renders;
@ -735,6 +736,12 @@ stash_stats(notcurses* nc){
if(nc->stashstats.writeout_min_ns > nc->stats.writeout_min_ns){ if(nc->stashstats.writeout_min_ns > nc->stats.writeout_min_ns){
nc->stashstats.writeout_min_ns = nc->stats.writeout_min_ns; nc->stashstats.writeout_min_ns = nc->stats.writeout_min_ns;
} }
if(nc->stashstats.raster_max_ns < nc->stats.raster_max_ns){
nc->stashstats.raster_max_ns = nc->stats.raster_max_ns;
}
if(nc->stashstats.raster_min_ns > nc->stats.raster_min_ns){
nc->stashstats.raster_min_ns = nc->stats.raster_min_ns;
}
nc->stashstats.cellelisions += nc->stats.cellelisions; nc->stashstats.cellelisions += nc->stats.cellelisions;
nc->stashstats.cellemissions += nc->stats.cellemissions; nc->stashstats.cellemissions += nc->stats.cellemissions;
nc->stashstats.fgelisions += nc->stats.fgelisions; nc->stashstats.fgelisions += nc->stats.fgelisions;
@ -1154,6 +1161,13 @@ int notcurses_stop(notcurses* nc){
fprintf(stderr, "\n%ju render%s, %ss total (%ss min, %ss max, %ss avg)\n", fprintf(stderr, "\n%ju render%s, %ss total (%ss min, %ss max, %ss avg)\n",
nc->stashstats.renders, nc->stashstats.renders == 1 ? "" : "s", nc->stashstats.renders, nc->stashstats.renders == 1 ? "" : "s",
totalbuf, minbuf, maxbuf, avgbuf); totalbuf, minbuf, maxbuf, avgbuf);
qprefix(nc->stashstats.raster_ns, NANOSECS_IN_SEC, totalbuf, 0);
qprefix(nc->stashstats.raster_min_ns, NANOSECS_IN_SEC, minbuf, 0);
qprefix(nc->stashstats.raster_max_ns, NANOSECS_IN_SEC, maxbuf, 0);
qprefix(nc->stashstats.raster_ns / nc->stashstats.writeouts, NANOSECS_IN_SEC, avgbuf, 0);
fprintf(stderr, "%ju raster%s, %ss total (%ss min, %ss max, %ss avg)\n",
nc->stashstats.writeouts, nc->stashstats.writeouts == 1 ? "" : "s",
totalbuf, minbuf, maxbuf, avgbuf);
qprefix(nc->stashstats.writeout_ns, NANOSECS_IN_SEC, totalbuf, 0); qprefix(nc->stashstats.writeout_ns, NANOSECS_IN_SEC, totalbuf, 0);
qprefix(nc->stashstats.writeout_min_ns, NANOSECS_IN_SEC, minbuf, 0); qprefix(nc->stashstats.writeout_min_ns, NANOSECS_IN_SEC, minbuf, 0);
qprefix(nc->stashstats.writeout_max_ns, NANOSECS_IN_SEC, maxbuf, 0); qprefix(nc->stashstats.writeout_max_ns, NANOSECS_IN_SEC, maxbuf, 0);