vtest: allow to save/replay tests

This is useful to do some quite accurate comparative
benchmarks/profiling, and to run fuzzers, such as american fuzzy lop.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
macos/master
Marc-André Lureau 9 years ago committed by Dave Airlie
parent 36492a4012
commit 1b736c547a
  1. 2
      vtest/vtest.h
  2. 55
      vtest/vtest_renderer.c
  3. 64
      vtest/vtest_server.c

@ -25,7 +25,7 @@
#define VTEST_H #define VTEST_H
#include <errno.h> #include <errno.h>
int vtest_create_renderer(int fd, uint32_t length); int vtest_create_renderer(int in_fd, int out_fd, uint32_t length);
int vtest_send_caps(void); int vtest_send_caps(void);

@ -25,6 +25,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include "virglrenderer.h" #include "virglrenderer.h"
#include <sys/uio.h> #include <sys/uio.h>
@ -47,7 +49,8 @@ struct virgl_renderer_callbacks vtest_cbs = {
}; };
struct vtest_renderer { struct vtest_renderer {
int remote_fd; int in_fd;
int out_fd;
}; };
struct vtest_renderer renderer; struct vtest_renderer renderer;
@ -78,6 +81,8 @@ int vtest_block_read(int fd, void *buf, int size)
void *ptr = buf; void *ptr = buf;
int left; int left;
int ret; int ret;
static int savefd = -1;
left = size; left = size;
do { do {
ret = read(fd, ptr, left); ret = read(fd, ptr, left);
@ -86,15 +91,30 @@ int vtest_block_read(int fd, void *buf, int size)
left -= ret; left -= ret;
ptr += ret; ptr += ret;
} while (left); } while (left);
if (getenv("VTEST_SAVE")) {
if (savefd == -1) {
savefd = open(getenv("VTEST_SAVE"),
O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC|O_DSYNC, S_IRUSR|S_IWUSR);
if (savefd == -1) {
perror("error opening save file");
exit(1);
}
}
if (write(savefd, buf, size) != size) {
perror("failed to save");
exit(1);
}
}
return size; return size;
} }
int vtest_create_renderer(int fd, uint32_t length) int vtest_create_renderer(int in_fd, int out_fd, uint32_t length)
{ {
char *vtestname; char *vtestname;
int ret; int ret;
renderer.remote_fd = fd; renderer.in_fd = in_fd;
renderer.out_fd = out_fd;
ret = virgl_renderer_init(&renderer, ret = virgl_renderer_init(&renderer,
VIRGL_RENDERER_USE_EGL | VIRGL_RENDERER_USE_EGL |
@ -108,7 +128,7 @@ int vtest_create_renderer(int fd, uint32_t length)
if (!vtestname) if (!vtestname)
return -1; return -1;
ret = vtest_block_read(renderer.remote_fd, vtestname, length); ret = vtest_block_read(renderer.in_fd, vtestname, length);
if (ret != length) { if (ret != length) {
ret = -1; ret = -1;
goto end; goto end;
@ -125,7 +145,8 @@ void vtest_destroy_renderer(void)
{ {
virgl_renderer_context_destroy(ctx_id); virgl_renderer_context_destroy(ctx_id);
virgl_renderer_cleanup(&renderer); virgl_renderer_cleanup(&renderer);
renderer.remote_fd = 0; renderer.in_fd = -1;
renderer.out_fd = -1;
} }
int vtest_send_caps(void) int vtest_send_caps(void)
@ -145,10 +166,10 @@ int vtest_send_caps(void)
hdr_buf[0] = max_size + 1; hdr_buf[0] = max_size + 1;
hdr_buf[1] = 1; hdr_buf[1] = 1;
ret = vtest_block_write(renderer.remote_fd, hdr_buf, 8); ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
if (ret < 0) if (ret < 0)
return ret; return ret;
vtest_block_write(renderer.remote_fd, caps_buf, max_size); vtest_block_write(renderer.out_fd, caps_buf, max_size);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -161,7 +182,7 @@ int vtest_create_resource(void)
struct virgl_renderer_resource_create_args args; struct virgl_renderer_resource_create_args args;
int ret; int ret;
ret = vtest_block_read(renderer.remote_fd, &res_create_buf, sizeof(res_create_buf)); ret = vtest_block_read(renderer.in_fd, &res_create_buf, sizeof(res_create_buf));
if (ret != sizeof(res_create_buf)) if (ret != sizeof(res_create_buf))
return -1; return -1;
@ -190,7 +211,7 @@ int vtest_resource_unref(void)
int ret; int ret;
uint32_t handle; uint32_t handle;
ret = vtest_block_read(renderer.remote_fd, &res_unref_buf, sizeof(res_unref_buf)); ret = vtest_block_read(renderer.in_fd, &res_unref_buf, sizeof(res_unref_buf));
if (ret != sizeof(res_unref_buf)) if (ret != sizeof(res_unref_buf))
return -1; return -1;
@ -209,7 +230,7 @@ int vtest_submit_cmd(uint32_t length_dw)
if (!cbuf) if (!cbuf)
return -1; return -1;
ret = vtest_block_read(renderer.remote_fd, cbuf, length_dw * 4); ret = vtest_block_read(renderer.in_fd, cbuf, length_dw * 4);
if (ret != length_dw * 4) if (ret != length_dw * 4)
return -1; return -1;
@ -246,7 +267,7 @@ int vtest_transfer_get(uint32_t length_dw)
void *ptr; void *ptr;
struct iovec iovec; struct iovec iovec;
ret = vtest_block_read(renderer.remote_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4); ret = vtest_block_read(renderer.in_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4);
if (ret != VCMD_TRANSFER_HDR_SIZE * 4) if (ret != VCMD_TRANSFER_HDR_SIZE * 4)
return ret; return ret;
@ -268,7 +289,7 @@ int vtest_transfer_get(uint32_t length_dw)
&iovec, 1); &iovec, 1);
if (ret) if (ret)
fprintf(stderr," transfer read failed %d\n", ret); fprintf(stderr," transfer read failed %d\n", ret);
ret = vtest_block_write(renderer.remote_fd, ptr, data_size); ret = vtest_block_write(renderer.out_fd, ptr, data_size);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -287,7 +308,7 @@ int vtest_transfer_put(uint32_t length_dw)
void *ptr; void *ptr;
struct iovec iovec; struct iovec iovec;
ret = vtest_block_read(renderer.remote_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4); ret = vtest_block_read(renderer.in_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4);
if (ret != VCMD_TRANSFER_HDR_SIZE * 4) if (ret != VCMD_TRANSFER_HDR_SIZE * 4)
return ret; return ret;
@ -297,7 +318,7 @@ int vtest_transfer_put(uint32_t length_dw)
if (!ptr) if (!ptr)
return -ENOMEM; return -ENOMEM;
ret = vtest_block_read(renderer.remote_fd, ptr, data_size); ret = vtest_block_read(renderer.in_fd, ptr, data_size);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -325,7 +346,7 @@ int vtest_resource_busy_wait(void)
uint32_t hdr_buf[VTEST_HDR_SIZE]; uint32_t hdr_buf[VTEST_HDR_SIZE];
uint32_t reply_buf[1]; uint32_t reply_buf[1];
bool busy = false; bool busy = false;
ret = vtest_block_read(renderer.remote_fd, &bw_buf, sizeof(bw_buf)); ret = vtest_block_read(renderer.in_fd, &bw_buf, sizeof(bw_buf));
if (ret != sizeof(bw_buf)) if (ret != sizeof(bw_buf))
return -1; return -1;
@ -351,11 +372,11 @@ int vtest_resource_busy_wait(void)
hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT; hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
reply_buf[0] = busy ? 1 : 0; reply_buf[0] = busy ? 1 : 0;
ret = vtest_block_write(renderer.remote_fd, hdr_buf, sizeof(hdr_buf)); ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = vtest_block_write(renderer.remote_fd, reply_buf, sizeof(reply_buf)); ret = vtest_block_write(renderer.out_fd, reply_buf, sizeof(reply_buf));
if (ret < 0) if (ret < 0)
return ret; return ret;

@ -30,6 +30,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/un.h> #include <sys/un.h>
#include <fcntl.h>
#include "util.h" #include "util.h"
#include "vtest.h" #include "vtest.h"
@ -85,23 +86,23 @@ int wait_for_socket_accept(int sock)
return -1; return -1;
} }
int run_renderer(int new_fd) int run_renderer(int in_fd, int out_fd)
{ {
int ret; int ret;
uint32_t header[VTEST_HDR_SIZE]; uint32_t header[VTEST_HDR_SIZE];
bool inited = false; bool inited = false;
again: again:
ret = vtest_wait_for_fd_read(new_fd); ret = vtest_wait_for_fd_read(in_fd);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
ret = vtest_block_read(new_fd, &header, sizeof(header)); ret = vtest_block_read(in_fd, &header, sizeof(header));
if (ret == 8) { if (ret == 8) {
if (!inited) { if (!inited) {
if (header[1] != VCMD_CREATE_RENDERER) if (header[1] != VCMD_CREATE_RENDERER)
goto fail; goto fail;
ret = vtest_create_renderer(new_fd, header[0]); ret = vtest_create_renderer(in_fd, out_fd, header[0]);
inited = true; inited = true;
} }
vtest_poll(); vtest_poll();
@ -144,23 +145,40 @@ again:
fail: fail:
fprintf(stderr, "socket failed - closing renderer\n"); fprintf(stderr, "socket failed - closing renderer\n");
vtest_destroy_renderer(); vtest_destroy_renderer();
close(new_fd); close(in_fd);
return 0; return 0;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int sock, new_fd; int ret, sock = -1, in_fd, out_fd;
pid_t pid; pid_t pid;
bool do_fork = true; bool do_fork = true, loop = true;
struct sigaction sa; struct sigaction sa;
if (argc > 1) { #ifdef __AFL_LOOP
while (__AFL_LOOP(1000)) {
#endif
if (argc > 1) {
if (!strcmp(argv[1], "--no-fork")) if (!strcmp(argv[1], "--no-fork"))
do_fork = false; do_fork = false;
else { else {
fprintf(stderr, "illegal command line parameter\n"); ret = open(argv[1], O_RDONLY);
exit(-1); if (ret == -1) {
perror(0);
exit(1);
}
in_fd = ret;
ret = open("/dev/null", O_WRONLY);
if (ret == -1) {
perror(0);
exit(1);
}
out_fd = ret;
loop = false;
do_fork = false;
goto start;
} }
} }
@ -176,23 +194,35 @@ int main(int argc, char **argv)
sock = vtest_open_socket("/tmp/.virgl_test"); sock = vtest_open_socket("/tmp/.virgl_test");
restart: restart:
new_fd = wait_for_socket_accept(sock); in_fd = wait_for_socket_accept(sock);
out_fd = in_fd;
start:
if (do_fork) { if (do_fork) {
/* fork a renderer process */ /* fork a renderer process */
switch ((pid = fork())) { switch ((pid = fork())) {
case 0: case 0:
run_renderer(new_fd); run_renderer(in_fd, out_fd);
exit(0); exit(0);
break; break;
case -1: case -1:
default: default:
close(new_fd); close(in_fd);
goto restart; if (loop)
goto restart;
} }
} else { } else {
run_renderer(new_fd); run_renderer(in_fd, out_fd);
goto restart; if (loop)
goto restart;
} }
close(sock);
if (sock != -1)
close(sock);
if (in_fd != out_fd)
close(out_fd);
#ifdef __AFL_LOOP
}
#endif
} }

Loading…
Cancel
Save