Merge pull request #160 from gwsystems/improve-image-resize

Improve image resize
main
Sean McBride 4 years ago committed by GitHub
commit f8113bf3c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,17 +0,0 @@
# Resize
Resizes Images
It appears that the initial request cuts off the bottom of the image. Thereafter, it seems that the runtime crashes out due to a socket error.
```
write: Bad file descriptor
C: 07, T: 0x7f20eed26700, F: current_sandbox_main>
Unable to build and send client response
C: 07, T: 0x7f20eed26700, F: client_socket_send>
Error sending to client: Bad file descriptor
C: 07, T: 0x7f20eed26700, F: sandbox_close_http> PANIC!
Bad file descriptor
find: 'result_13192.jpg': No such file or directory
```

@ -0,0 +1,5 @@
# Resize Image by Resolution
The goal of this experiment is to run the resize operation on small, medium, and large source images and measure how the size of the input image affects execution time.
The workload works sporadically, but the runtime errors out due to calls to `mremap`. The runtime gratuitously logs these calls for the time being.

@ -5,7 +5,7 @@
# Also disables pagination and stopping on SIGUSR1
experiment_directory=$(pwd)
project_directory=$(cd ../../.. && pwd)
project_directory=$(cd ../../../.. && pwd)
binary_directory=$(cd "$project_directory"/bin && pwd)
export LD_LIBRARY_PATH="$binary_directory:$LD_LIBRARY_PATH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -0,0 +1,70 @@
#!/bin/bash
# Executes the runtime in GDB
# Substitutes the absolute path from the container with a path relatively derived from the location of this script
# This allows debugging outside of the Docker container
# Also disables pagination and stopping on SIGUSR1
experiment_directory=$(pwd)
project_directory=$(cd ../../../.. && pwd)
binary_directory=$(cd "$project_directory"/bin && pwd)
# Copy Flower Image if not here
if [[ ! -f "./flower.jpg" ]]; then
cp ../../../../tests/sod/bin/flower.jpg ./flower.jpg
fi
if [ "$1" != "-d" ]; then
PATH="$binary_directory:$PATH" LD_LIBRARY_PATH="$binary_directory:$LD_LIBRARY_PATH" sledgert "$experiment_directory/spec.json" &
sleep 1
else
echo "Running under gdb"
fi
success_count=0
total_count=10
for ((i = 0; i < total_count; i++)); do
echo "$i"
ext="$RANDOM"
curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@shrinking_man_small.jpg" --output "result_${ext}_small.png" localhost:10000 2>/dev/null 1>/dev/null
pixel_differences="$(compare -identify -metric AE "result_${ext}_small.png" expected_result.png null: 2>&1 >/dev/null)"
if [[ "$pixel_differences" == "0" ]]; then
success_count=$((success_count + 1))
else
echo "Small FAIL"
echo "$pixel_differences pixel differences detected"
exit
fi
curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@shrinking_man_medium.jpg" --output "result_${ext}_medium.png" localhost:10001 2>/dev/null 1>/dev/null
pixel_differences="$(compare -identify -metric AE "result_${ext}_medium.png" expected_result.png null: 2>&1 >/dev/null)"
if [[ "$pixel_differences" == "0" ]]; then
success_count=$((success_count + 1))
else
echo "Medium FAIL"
echo "$pixel_differences pixel differences detected"
exit
fi
curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@shrinking_man_large.jpg" --output "result_${ext}_large.png" localhost:10002 2>/dev/null 1>/dev/null
pixel_differences="$(compare -identify -metric AE "result_${ext}_large.png" expected_result.png null: 2>&1 >/dev/null)"
if [[ "$pixel_differences" == "0" ]]; then
success_count=$((success_count + 1))
else
echo "Large FAIL"
echo "$pixel_differences pixel differences detected"
exit
fi
done
echo "$success_count / $total_count"
rm result_*.png
if [ "$1" != "-d" ]; then
sleep 5
echo -n "Running Cleanup: "
pkill sledgert >/dev/null 2>/dev/null
echo "[DONE]"
fi

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

@ -0,0 +1,42 @@
{
"active": "yes",
"name": "resize_small",
"path": "resize_wasm.so",
"port": 10000,
"relative-deadline-us": 50000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "image/jpeg",
"http-req-size": 1024000,
"http-resp-headers": [],
"http-resp-size": 1024000,
"http-resp-content-type": "image/png"
}
{
"active": "yes",
"name": "resize_medium",
"path": "resize_wasm.so",
"port": 10001,
"relative-deadline-us": 50000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "image/jpeg",
"http-req-size": 1024000,
"http-resp-headers": [],
"http-resp-size": 1024000,
"http-resp-content-type": "image/png"
}
{
"active": "yes",
"name": "resize_large",
"path": "resize_wasm.so",
"port": 10002,
"relative-deadline-us": 50000,
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "image/jpeg",
"http-req-size": 1024000,
"http-resp-headers": [],
"http-resp-size": 1024000,
"http-resp-content-type": "image/png"
}

@ -0,0 +1,5 @@
# Resize Images
This script runs several test executions of the resize application, testing that the output is pixel-for-pixel identical to a known good output.
The workload works sporadically, but the runtime errors out due to calls to `mremap`. The runtime gratuitously logs these calls for the time being.

@ -0,0 +1,19 @@
#!/bin/bash
# Executes the runtime in GDB
# Substitutes the absolute path from the container with a path relatively derived from the location of this script
# This allows debugging outside of the Docker container
# Also disables pagination and stopping on SIGUSR1
experiment_directory=$(pwd)
project_directory=$(cd ../../../.. && pwd)
binary_directory=$(cd "$project_directory"/bin && pwd)
export LD_LIBRARY_PATH="$binary_directory:$LD_LIBRARY_PATH"
export PATH="$binary_directory:$PATH"
gdb --eval-command="handle SIGUSR1 nostop" \
--eval-command="handle SIGPIPE nostop" \
--eval-command="set pagination off" \
--eval-command="set substitute-path /sledge/runtime $project_directory" \
--eval-command="run $experiment_directory/spec.json" \
sledgert

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -5,12 +5,12 @@
# Also disables pagination and stopping on SIGUSR1
experiment_directory=$(pwd)
project_directory=$(cd ../../.. && pwd)
project_directory=$(cd ../../../.. && pwd)
binary_directory=$(cd "$project_directory"/bin && pwd)
# Copy Flower Image if not here
if [[ ! -f "./flower.jpg" ]]; then
cp ../../../tests/sod/bin/flower.jpg ./flower.jpg
cp ../../../../tests/sod/bin/flower.jpg ./flower.jpg
fi
if [ "$1" != "-d" ]; then
@ -20,42 +20,31 @@ else
echo "Running under gdb"
fi
# expected_result="$(cat ./expected_result.jpg)"
expected_size="$(find expected_result.jpg -printf "%s")"
success_count=0
total_count=50
# curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@flower.jpg" --output result.jpg localhost:10000
# WIP
# exit
total_count=10
for ((i = 0; i < total_count; i++)); do
echo "$i"
ext="$RANDOM"
curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@flower.jpg" --output "result_$ext.jpg" localhost:10000 2>/dev/null
actual_size="$(find result_"$ext".jpg -printf "%s")"
curl -H 'Expect:' -H "Content-Type: image/jpg" --data-binary "@flower.jpg" --output "result_$ext.png" localhost:10000 2>/dev/null 1>/dev/null
pixel_differences="$(compare -identify -metric AE "result_$ext.png" expected_result.png null: 2>&1 >/dev/null)"
# echo "$result"
if [[ "$expected_size" == "$actual_size" ]]; then
if [[ "$pixel_differences" == "0" ]]; then
success_count=$((success_count + 1))
rm result.jpg
else
echo "FAIL"
echo "Expected Size:"
echo "$expected_size"
echo "==============================================="
echo "Actual Size:"
echo "$actual_size"
echo "$pixel_differences pixel differences detected"
exit
fi
done
echo "$success_count / $total_count"
rm result_*.png
if [ "$1" != "-d" ]; then
sleep 5
echo -n "Running Cleanup: "
rm result_*.jpg
pkill sledgert >/dev/null 2>/dev/null
echo "[DONE]"
fi

@ -7,8 +7,8 @@
"argsize": 1,
"http-req-headers": [],
"http-req-content-type": "image/jpeg",
"http-req-size": 102400,
"http-req-size": 1024000,
"http-resp-headers": [],
"http-resp-size": 102400,
"http-resp-size": 1024000,
"http-resp-content-type": "image/png"
}

@ -15,7 +15,12 @@
static inline void
client_socket_close(int client_socket)
{
if (close(client_socket) < 0) debuglog("Error closing client socket - %s", strerror(errno));
/* Should never close 0, 1, or 2 */
assert(client_socket != STDIN_FILENO);
assert(client_socket != STDOUT_FILENO);
assert(client_socket != STDERR_FILENO);
if (unlikely(close(client_socket) < 0)) debuglog("Error closing client socket - %s", strerror(errno));
}
@ -50,6 +55,8 @@ client_socket_send(int client_socket, int status_code)
if (rc < 0) {
if (errno == EAGAIN) { debuglog("Unexpectedly blocking on write of %s\n", response); }
debuglog("Error with %s\n", strerror(errno));
goto send_err;
}
sent += rc;

@ -238,6 +238,10 @@ int32_t
wasm_close(int32_t io_handle_index)
{
int fd = current_sandbox_get_file_descriptor(io_handle_index);
// Silently disregard client requests to close STDIN, STDOUT, or STDERR
if (fd <= STDERR_FILENO) return 0;
int32_t res = (int32_t)close(fd);
if (res == -1) return -errno;
@ -504,6 +508,26 @@ wasm_writev(int32_t fd, int32_t iov_offset, int32_t iovcnt)
return res;
}
#define SYS_MREMAP 25
#define MREMAP_MAYMOVE 1
#define MREMAP_FIXED 2
int32_t
wasm_mremap(int32_t offset, int32_t old_size, int32_t new_size, int32_t flags)
{
/* Should fit within the 32-bit linear address space */
/* TODO: Improve with errno */
assert(offset + old_size < INT32_MAX);
assert(new_size < INT32_MAX);
/* Not really implemented, so dump out usage to understand requirements */
debuglog("Offset: %d, Old Size: %d, New Size: %d, May Move: %s, Fixed: %s\n", offset, old_size, new_size,
(flags & MREMAP_MAYMOVE) == MREMAP_MAYMOVE ? "true" : "false",
(flags & MREMAP_FIXED) == MREMAP_FIXED ? "true" : "false");
/* Return the current offset, hoping for the best */
return offset;
}
#define SYS_MADVISE 28
#define SYS_GETPID 39
@ -730,6 +754,8 @@ inner_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int
case SYS_SET_THREAD_AREA:
case SYS_SET_TID_ADDRESS:
case SYS_BRK:
case SYS_MREMAP:
return wasm_mremap(a, b, c, b);
case SYS_MADVISE:
/* Note: These are called, but are unimplemented and fail silently */
return 0;

@ -34,16 +34,20 @@ module_listen(struct module *module)
/* Allocate a new TCP/IP socket, setting it to be non-blocking */
int socket_descriptor = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (socket_descriptor < 0) goto err_create_socket;
if (unlikely(socket_descriptor < 0)) goto err_create_socket;
/* Socket should never have returned on fd 0, 1, or 2 */
assert(socket_descriptor != STDIN_FILENO);
assert(socket_descriptor != STDOUT_FILENO);
assert(socket_descriptor != STDERR_FILENO);
/* Configure the socket to allow multiple sockets to bind to the same host and port */
int optval = 1;
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
if (rc < 0) goto err_set_socket_option;
if (unlikely(rc < 0)) goto err_set_socket_option;
optval = 1;
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (rc < 0) goto err_set_socket_option;
if (unlikely(rc < 0)) goto err_set_socket_option;
/* Bind name [all addresses]:[module->port] to socket */
module->socket_descriptor = socket_descriptor;
@ -51,11 +55,11 @@ module_listen(struct module *module)
module->socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
module->socket_address.sin_port = htons((unsigned short)module->port);
rc = bind(socket_descriptor, (struct sockaddr *)&module->socket_address, sizeof(module->socket_address));
if (rc < 0) goto err_bind_socket;
if (unlikely(rc < 0)) goto err_bind_socket;
/* Listen to the interface */
rc = listen(socket_descriptor, MODULE_MAX_PENDING_CLIENT_REQUESTS);
if (rc < 0) goto err_listen;
if (unlikely(rc < 0)) goto err_listen;
/* Set the socket descriptor and register with our global epoll instance to monitor for incoming HTTP
@ -64,7 +68,7 @@ module_listen(struct module *module)
accept_evt.data.ptr = (void *)module;
accept_evt.events = EPOLLIN;
rc = epoll_ctl(runtime_epoll_file_descriptor, EPOLL_CTL_ADD, module->socket_descriptor, &accept_evt);
if (rc < 0) goto err_add_to_epoll;
if (unlikely(rc < 0)) goto err_add_to_epoll;
rc = 0;
done:

@ -152,12 +152,17 @@ listener_thread_main(void *dummy)
int client_socket = accept4(module->socket_descriptor,
(struct sockaddr *)&client_address, &address_length,
SOCK_NONBLOCK);
if (client_socket < 0) {
if (unlikely(client_socket < 0)) {
if (errno == EWOULDBLOCK || errno == EAGAIN) break;
panic("accept4: %s", strerror(errno));
}
/* We should never have accepted on fd 0, 1, or 2 */
assert(client_socket != STDIN_FILENO);
assert(client_socket != STDOUT_FILENO);
assert(client_socket != STDERR_FILENO);
/*
* According to accept(2), it is possible that the the sockaddr structure client_address
* may be too small, resulting in data being truncated to fit. The appect call mutates

@ -169,11 +169,16 @@ connect_n_send(void)
{
int socket_descriptor;
if ((socket_descriptor = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if (unlikely((socket_descriptor = socket(AF_INET, SOCK_STREAM, 0)) < 0)) {
perror("socket");
return -1;
}
/* Should never receive sockets 0, 1, or 2 */
assert(socket_descriptor != STDIN_FILENO);
assert(socket_descriptor != STDOUT_FILENO);
assert(socket_descriptor != STDERR_FILENO);
struct sockaddr_in socket_address;
socket_address.sin_family = AF_INET;
socket_address.sin_port = htons(SERVER_PORT);

Loading…
Cancel
Save