mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-13 05:33:51 -04:00
pgo: feed VT data through fdm_ptmx(), not vt_from_slave()
fdm_ptmx(), the FDM callback handler for ptmx data, is just as much in the hot path as vt_from_slave(). It is also slightly more complicated than a read() followed by a call to vt_from_slave(). As a result, some benchmarks performed significantly worse in a partial PGO build than in a full PGO build, since fdm_ptmx() wasn’t PGO:d. To be able to feed data through fdm_ptmx(), we need to set up the delayed rendering timer FDs, configure the timeout values, and provide a readable FD it can read the VT data from. The latter is done with a memory FD. This ensures *all* VT data is loaded into memory before we feed it to the parser.
This commit is contained in:
parent
ecaa3b4135
commit
daa8d129c1
2 changed files with 64 additions and 7 deletions
67
pgo/pgo.c
67
pgo/pgo.c
|
|
@ -6,12 +6,18 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "async.h"
|
#include "async.h"
|
||||||
|
#include "config.h"
|
||||||
#include "user-notification.h"
|
#include "user-notification.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
|
||||||
|
extern bool fdm_ptmx(struct fdm *fdm, int fd, int events, void *data);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(const char *prog_name)
|
usage(const char *prog_name)
|
||||||
{
|
{
|
||||||
|
|
@ -131,12 +137,29 @@ main(int argc, const char *const *argv)
|
||||||
const int col_count = 135;
|
const int col_count = 135;
|
||||||
const int grid_row_count = 16384;
|
const int grid_row_count = 16384;
|
||||||
|
|
||||||
|
int lower_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||||
|
if (lower_fd < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
int upper_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||||
|
if (upper_fd < 0) {
|
||||||
|
close(lower_fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
struct row **rows = calloc(grid_row_count, sizeof(rows[0]));
|
struct row **rows = calloc(grid_row_count, sizeof(rows[0]));
|
||||||
for (int i = 0; i < grid_row_count; i++) {
|
for (int i = 0; i < grid_row_count; i++) {
|
||||||
rows[i] = calloc(1, sizeof(*rows[i]));
|
rows[i] = calloc(1, sizeof(*rows[i]));
|
||||||
rows[i]->cells = calloc(col_count, sizeof(rows[i]->cells[0]));
|
rows[i]->cells = calloc(col_count, sizeof(rows[i]->cells[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct config conf = {
|
||||||
|
.tweak = {
|
||||||
|
.delayed_render_lower_ns = 500000, /* 0.5ms */
|
||||||
|
.delayed_render_upper_ns = 16666666 / 2, /* half a frame period (60Hz) */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
struct wayland wayl = {
|
struct wayland wayl = {
|
||||||
.seats = tll_init(),
|
.seats = tll_init(),
|
||||||
.monitors = tll_init(),
|
.monitors = tll_init(),
|
||||||
|
|
@ -144,6 +167,7 @@ main(int argc, const char *const *argv)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct terminal term = {
|
struct terminal term = {
|
||||||
|
.conf = &conf,
|
||||||
.wl = &wayl,
|
.wl = &wayl,
|
||||||
.grid = &term.normal,
|
.grid = &term.normal,
|
||||||
.normal = {
|
.normal = {
|
||||||
|
|
@ -173,6 +197,10 @@ main(int argc, const char *const *argv)
|
||||||
.start = {-1, -1},
|
.start = {-1, -1},
|
||||||
.end = {-1, -1},
|
.end = {-1, -1},
|
||||||
},
|
},
|
||||||
|
.delayed_render_timer = {
|
||||||
|
.lower_fd = lower_fd,
|
||||||
|
.upper_fd = upper_fd
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tll_push_back(wayl.terms, &term);
|
tll_push_back(wayl.terms, &term);
|
||||||
|
|
@ -182,37 +210,62 @@ main(int argc, const char *const *argv)
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(argv[i], &st) < 0) {
|
if (stat(argv[i], &st) < 0) {
|
||||||
fprintf(stderr, "error: %s: failed to stat: %s",
|
fprintf(stderr, "error: %s: failed to stat: %s\n",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *data = malloc(st.st_size);
|
uint8_t *data = malloc(st.st_size);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
fprintf(stderr, "error: %s: failed to allocate buffer: %s",
|
fprintf(stderr, "error: %s: failed to allocate buffer: %s\n",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = open(argv[1], O_RDONLY);
|
int fd = open(argv[1], O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "error: %s: failed to open: %s",
|
fprintf(stderr, "error: %s: failed to open: %s\n",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t amount = read(fd, data, st.st_size);
|
ssize_t amount = read(fd, data, st.st_size);
|
||||||
if (amount != st.st_size) {
|
if (amount != st.st_size) {
|
||||||
fprintf(stderr, "error: %s: failed to read: %s",
|
fprintf(stderr, "error: %s: failed to read: %s\n",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
printf("Feeding VT parser with %s\n", argv[i]);
|
int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
|
||||||
vt_from_slave(&term, data, st.st_size);
|
if (mem_fd < 0) {
|
||||||
|
fprintf(stderr, "error: failed to create memory FD\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(mem_fd, data, st.st_size) < 0) {
|
||||||
|
fprintf(stderr, "error: failed to write memory FD\n");
|
||||||
|
close(mem_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
|
term.ptmx = mem_fd;
|
||||||
|
lseek(mem_fd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
printf("Feeding VT parser with %s (%lld bytes)\n",
|
||||||
|
argv[i], (long long)st.st_size);
|
||||||
|
|
||||||
|
while (lseek(mem_fd, 0, SEEK_CUR) < st.st_size) {
|
||||||
|
if (!fdm_ptmx(NULL, -1, EPOLLIN, &term)) {
|
||||||
|
fprintf(stderr, "error: fdm_ptmx() failed\n");
|
||||||
|
close(mem_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(mem_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = EXIT_SUCCESS;
|
ret = EXIT_SUCCESS;
|
||||||
|
|
@ -226,5 +279,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rows);
|
free(rows);
|
||||||
|
close(lower_fd);
|
||||||
|
close(upper_fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,9 @@ fdm_ptmx_out(struct fdm *fdm, int fd, int events, void *data)
|
||||||
static struct timespec last = {0};
|
static struct timespec last = {0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
/* Externally visible, but not declared in terminal.h, to enable pgo
|
||||||
|
* to call this function directly */
|
||||||
|
bool
|
||||||
fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
||||||
{
|
{
|
||||||
struct terminal *term = data;
|
struct terminal *term = data;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue