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
#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);

@ -25,6 +25,8 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "virglrenderer.h"
#include <sys/uio.h>
@ -47,7 +49,8 @@ struct virgl_renderer_callbacks vtest_cbs = {
};
struct vtest_renderer {
int remote_fd;
int in_fd;
int out_fd;
};
struct vtest_renderer renderer;
@ -78,6 +81,8 @@ int vtest_block_read(int fd, void *buf, int size)
void *ptr = buf;
int left;
int ret;
static int savefd = -1;
left = size;
do {
ret = read(fd, ptr, left);
@ -86,15 +91,30 @@ int vtest_block_read(int fd, void *buf, int size)
left -= ret;
ptr += ret;
} 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;
}
int vtest_create_renderer(int fd, uint32_t length)
int vtest_create_renderer(int in_fd, int out_fd, uint32_t length)
{
char *vtestname;
int ret;
renderer.remote_fd = fd;
renderer.in_fd = in_fd;
renderer.out_fd = out_fd;
ret = virgl_renderer_init(&renderer,
VIRGL_RENDERER_USE_EGL |
@ -108,7 +128,7 @@ int vtest_create_renderer(int fd, uint32_t length)
if (!vtestname)
return -1;
ret = vtest_block_read(renderer.remote_fd, vtestname, length);
ret = vtest_block_read(renderer.in_fd, vtestname, length);
if (ret != length) {
ret = -1;
goto end;
@ -125,7 +145,8 @@ void vtest_destroy_renderer(void)
{
virgl_renderer_context_destroy(ctx_id);
virgl_renderer_cleanup(&renderer);
renderer.remote_fd = 0;
renderer.in_fd = -1;
renderer.out_fd = -1;
}
int vtest_send_caps(void)
@ -145,10 +166,10 @@ int vtest_send_caps(void)
hdr_buf[0] = max_size + 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)
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)
return ret;
@ -161,7 +182,7 @@ int vtest_create_resource(void)
struct virgl_renderer_resource_create_args args;
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))
return -1;
@ -190,7 +211,7 @@ int vtest_resource_unref(void)
int ret;
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))
return -1;
@ -209,7 +230,7 @@ int vtest_submit_cmd(uint32_t length_dw)
if (!cbuf)
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)
return -1;
@ -246,7 +267,7 @@ int vtest_transfer_get(uint32_t length_dw)
void *ptr;
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)
return ret;
@ -268,7 +289,7 @@ int vtest_transfer_get(uint32_t length_dw)
&iovec, 1);
if (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)
return ret;
@ -287,7 +308,7 @@ int vtest_transfer_put(uint32_t length_dw)
void *ptr;
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)
return ret;
@ -297,7 +318,7 @@ int vtest_transfer_put(uint32_t length_dw)
if (!ptr)
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)
return ret;
@ -325,7 +346,7 @@ int vtest_resource_busy_wait(void)
uint32_t hdr_buf[VTEST_HDR_SIZE];
uint32_t reply_buf[1];
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))
return -1;
@ -351,11 +372,11 @@ int vtest_resource_busy_wait(void)
hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
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)
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)
return ret;

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