From 7109fdf42d3c5bb0db0fd9c1983ca9664f131308 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Tue, 17 Jan 2023 11:04:47 +0100 Subject: [PATCH 1/2] feat(asan): Address sanitizer (ASAN) tests and utility build system in test/ to run a utility that uses opencv to do the reading, RGBA conversion and screen play with filters, without applying parameters for now. using both gcc and clang and ASAN debug also improved test util to generate metadata of each plugin --- CMakeLists.txt | 1 + GNUmakefile | 12 +++ test/Makefile | 25 +++++- test/extract-plugin-info.sh | 14 +++ test/frei0r-info.c | 2 +- test/frei0r-test.c | 170 ++++++++++++++++++++++++++++++++++++ 6 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 GNUmakefile create mode 100755 test/extract-plugin-info.sh create mode 100644 test/frei0r-test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 731c108b..dd8d0e97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ endif (NOT CMAKE_BUILD_TYPE) set (LIBDIR "${CMAKE_INSTALL_LIBDIR}/frei0r-1") set (FREI0R_DEF "${CMAKE_SOURCE_DIR}/msvc/frei0r_1_0.def") set (FREI0R_1_1_DEF "${CMAKE_SOURCE_DIR}/msvc/frei0r_1_1.def") +set (FREI0R_1_2_DEF "${CMAKE_SOURCE_DIR}/msvc/frei0r_1_2.def") # --- custom targets: --- INCLUDE( cmake/modules/TargetDistclean.cmake OPTIONAL) diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 00000000..ab3a8b5e --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,12 @@ + + +debug: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -DCMAKE_C_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' .. + cd build && make + + +debug-clang-ninja: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -DCMAKE_C_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -G 'Ninja' .. + cd build && ninja diff --git a/test/Makefile b/test/Makefile index 70e924c0..a2bdc58c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,7 +2,21 @@ INCLUDES ?= -I ../include PLUGINDIR ?= ../build/src -all: build scan-plugins +CXX ?= g++ +DEBUG_FLAGS ?= -O0 -g -ggdb -Wl,-undefined -Wl,dynamic_lookup -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope + +all: test-utils +# build scan-plugins + +frei0r-test: CVFLAGS := $(shell pkg-config --libs --cflags opencv4) +frei0r-test: frei0r-test.c + ${CXX} ${DEBUG_FLAGS} -ggdb -O0 -I../include -o frei0r-test frei0r-test.c ${CVFLAGS} -ldl + +test-all-filters: frei0r-test + @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) + @find ${PLUGINDIR} -type f -name '*.so' -exec ./frei0r-test -t -v ${HOME}/Downloads/frei0r-all.webm -p {} \; + +# @$(if $(wildcard frei0r-test),,make test-utils) scan-plugins: @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) @@ -13,10 +27,17 @@ scan-plugins: @rm tmp.json $(info frei0r-plugin-list.json) + + +generate-metadata: EXTENSION ?= so +generate-metadata: + @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) + sh extract-plugin-info.sh ${EXTENSION} ${PLUGINDIR} + build: @${CC} -o frei0r-info -ggdb frei0r-info.c ${INCLUDES} clean: rm -f *.o - rm -f frei0r-info + rm -f frei0r-info frei0r-test rm -f *.json diff --git a/test/extract-plugin-info.sh b/test/extract-plugin-info.sh new file mode 100755 index 00000000..40dd77d0 --- /dev/null +++ b/test/extract-plugin-info.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +[ -r frei0r-info ] || gmake +tmp=`mktemp` +find "${2}" -name "*.$1" | + while read -r line; do + file=`basename $line` + dir=`dirname $line` + name=`echo $file | cut -d. -f1` + ./frei0r-info "$line" > $tmp + mv $tmp "$dir/$name.json" + ls "$dir/$name.json" + done +rm -f $tmp diff --git a/test/frei0r-info.c b/test/frei0r-info.c index de030853..803043ab 100644 --- a/test/frei0r-info.c +++ b/test/frei0r-info.c @@ -95,7 +95,7 @@ int main(int argc, char **argv) { } fprintf(stdout," ]\n"); } - fprintf(stdout,"\n},\n"); + fprintf(stdout,"\n}\n"); fflush(stdout); f0r_deinit(); dlclose(dl_handle); diff --git a/test/frei0r-test.c b/test/frei0r-test.c new file mode 100644 index 00000000..b949c889 --- /dev/null +++ b/test/frei0r-test.c @@ -0,0 +1,170 @@ +#include +#include +#include + +#include + +#include + +// frei0r function prototypes +typedef int (*f0r_init_f)(void); +typedef void (*f0r_deinit_f)(void); +typedef void (*f0r_get_plugin_info_f)(f0r_plugin_info_t *info); +typedef void (*f0r_get_param_info_f)(f0r_param_info_t *info, int param_index); +typedef f0r_instance_t (*f0r_construct_f)(unsigned int width, unsigned int height); +typedef void (*f0r_update_f)(f0r_instance_t instance, + double time, const uint32_t* inframe, uint32_t* outframe); +typedef void (*f0r_destruct_f)(f0r_instance_t instance); + + +int main(int argc, char* argv[]) { + // instance frei0r pointers + static void *dl_handle; + static f0r_init_f f0r_init; + static f0r_deinit_f f0r_deinit; + static f0r_plugin_info_t pi; + static f0r_get_plugin_info_f f0r_get_plugin_info; + static f0r_get_param_info_f f0r_get_param_info; + static f0r_param_info_t param; + static f0r_instance_t instance; + static f0r_construct_f f0r_construct; + static f0r_update_f f0r_update; + static f0r_destruct_f f0r_destruct; + + const char *usage = "Usage: frei0r-test [-td] "; + if (argc <3) { + fprintf(stderr,"%s\n",usage); + return -1; + } + + int opt; + int headless = 0; + int debug = 0; + char video_file[512]; + char plugin_file[512]; + while((opt = getopt(argc, argv, "tdv:p:")) != -1) { + switch(opt) { + case 't': + headless = 1; + break; + case 'd': + debug = 1; + break; + case 'p': + snprintf(plugin_file, 511, "%s", optarg); + break; + case 'v': + snprintf(video_file, 511, "%s", optarg); + break; + } + } + + // Open the image file using OpenCV + cv::VideoCapture cap(video_file); + if (!cap.isOpened()) { + printf("Error opening image file\n"); + return -1; + } + // Get video properties + int frame_width = (int) cap.get(cv::CAP_PROP_FRAME_WIDTH); + int frame_height = (int) cap.get(cv::CAP_PROP_FRAME_HEIGHT); + int fps = (int) cap.get(cv::CAP_PROP_FPS); + + const char *file = basename(plugin_file); + const char *dir = dirname(plugin_file); + char path[256];; + snprintf(path, 255,"%s/%s",dir,file); + // fprintf(stderr,"%s %s\n",argv[0], file); + // load shared library + dl_handle = dlopen(path, RTLD_NOW|RTLD_LOCAL|RTLD_NODELETE); + if(!dl_handle) { + fprintf(stderr,"error: %s\n",dlerror()); + exit(1); + } + // get plugin function calls + f0r_init = (f0r_init_f) dlsym(dl_handle,"f0r_init"); + f0r_deinit = (f0r_deinit_f) dlsym(dl_handle,"f0r_deinit"); + f0r_get_plugin_info = (f0r_get_plugin_info_f) dlsym(dl_handle,"f0r_get_plugin_info"); + f0r_get_param_info = (f0r_get_param_info_f) dlsym(dl_handle,"f0r_get_param_info"); + f0r_construct = (f0r_construct_f) dlsym(dl_handle,"f0r_construct"); + f0r_update = (f0r_update_f) dlsym(dl_handle,"f0r_update"); + f0r_destruct = (f0r_destruct_f) dlsym(dl_handle,"f0r_destruct"); + + // always initialize plugin first + f0r_init(); + // get info about plugin + f0r_get_plugin_info(&pi); + const char *frei0r_color_model = (pi.color_model == F0R_COLOR_MODEL_BGRA8888 ? "bgra8888" : + pi.color_model == F0R_COLOR_MODEL_RGBA8888 ? "rgba8888" : + pi.color_model == F0R_COLOR_MODEL_PACKED32 ? "packed32" : "unknown"); + + fprintf(stderr,"{\n \"name\":\"%s\",\n \"type\":\"%s\",\n \"color_model\":\"%s\",\n \"num_params\":\"%d\"\n}", + pi.name, + pi.plugin_type == F0R_PLUGIN_TYPE_FILTER ? "filter" : + pi.plugin_type == F0R_PLUGIN_TYPE_SOURCE ? "source" : + pi.plugin_type == F0R_PLUGIN_TYPE_MIXER2 ? "mixer2" : + pi.plugin_type == F0R_PLUGIN_TYPE_MIXER3 ? "mixer3" : "unknown", + frei0r_color_model, + pi.num_params); + + // TODO: just filters for now + if( pi.plugin_type != F0R_PLUGIN_TYPE_FILTER ) { + fprintf(stderr,"Plugin is not of filter type, skip for now\n"); + cap.release(); + f0r_deinit(); + dlclose(dl_handle); + exit(0); + } + if( pi.color_model != F0R_COLOR_MODEL_RGBA8888 ) { + fprintf(stderr,"Filter color model not supported: %s\n",frei0r_color_model); + cap.release(); + f0r_deinit(); + dlclose(dl_handle); + exit(1); + } + + instance = f0r_construct(frame_width, frame_height); + + // Create a window to display the video + if(!headless) { + cv::namedWindow("frei0r", cv::WINDOW_NORMAL); + cv::resizeWindow("frei0r", frame_width, frame_height); + cv::namedWindow("source", cv::WINDOW_NORMAL); + cv::resizeWindow("source", frame_width, frame_height); + } + + uint32_t *buffer; + /* //posix_memalign( (void**) &outframe, 16, frame_width * frame_height * 4 ); */ + buffer = (uint32_t*)calloc(4, frame_width * frame_height ); + + // Read the image file frame by frame + cv::Mat frame; + while (cap.read(frame)) { + // Convert the OpenCV image to an RGBA pixel buffer + cv::Mat frame_rgba; + cv::cvtColor(frame, frame_rgba, cv::COLOR_RGB2RGBA); + + // Create an SDL2 surface from the RGBA pixel buffer + f0r_update(instance, 0.0, (const uint32_t*)frame_rgba.data, buffer); + + // Display the frames + if(!headless) { + cv::imshow("source", frame); + memcpy(frame_rgba.data, buffer, frame_width * frame_height * 4); + cv::imshow("frei0r", frame_rgba); + // Wait for a key press + if(cv::waitKey(1000/fps) >= 0) break; + } + } + + free(buffer); + + cap.release(); // Release the video capture object + + f0r_destruct(instance); + f0r_deinit(); + + dlclose(dl_handle); + + return 0; +} From b6e6a624fbc666dcc501db027c4c6b2c78c026ec Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 12 May 2023 09:49:27 +0200 Subject: [PATCH 2/2] improve build system test suite and release builds --- GNUmakefile | 27 +++++++++++++++++++++- test/Makefile | 33 +++++++++++++++++---------- test/{frei0r-info.c => frei0r-meta.c} | 0 test/{frei0r-test.c => frei0r-run.c} | 0 4 files changed, 47 insertions(+), 13 deletions(-) rename test/{frei0r-info.c => frei0r-meta.c} (100%) rename test/{frei0r-test.c => frei0r-run.c} (100%) diff --git a/GNUmakefile b/GNUmakefile index ab3a8b5e..a333c5c2 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,6 +1,28 @@ +all: release-gcc-ninja +debug: debug-gcc -debug: +release-gcc: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release .. + cd build && make + +release-gcc-ninja: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release -G 'Ninja' .. + cd build && ninja + +release-clang: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release .. + cd build && make + +release-clang-ninja: + mkdir -p build + cd build && cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -G 'Ninja' .. + cd build && ninja + +debug-gcc: mkdir -p build cd build && cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -DCMAKE_C_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' .. cd build && make @@ -10,3 +32,6 @@ debug-clang-ninja: mkdir -p build cd build && cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -DCMAKE_C_FLAGS_DEBUG='-ggdb -fno-omit-frame-pointer -fsanitize=address' -G 'Ninja' .. cd build && ninja + +clean: + rm -rf build diff --git a/test/Makefile b/test/Makefile index a2bdc58c..0a2db26d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,22 +5,34 @@ PLUGINDIR ?= ../build/src CXX ?= g++ DEBUG_FLAGS ?= -O0 -g -ggdb -Wl,-undefined -Wl,dynamic_lookup -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope -all: test-utils +all: frei0r-meta frei0r-run + @echo "Test targets available:" + @echo "scan-meta :: scan all plugins and produce metadata" + @echo "check-asan :: run all tests on all plugins" + @echo "frei0r-meta :: build metadata plugin scanner" + @echo "frei0r-run :: build ASAN test utility" + + # build scan-plugins -frei0r-test: CVFLAGS := $(shell pkg-config --libs --cflags opencv4) -frei0r-test: frei0r-test.c - ${CXX} ${DEBUG_FLAGS} -ggdb -O0 -I../include -o frei0r-test frei0r-test.c ${CVFLAGS} -ldl +frei0r-run: CVFLAGS := $(shell pkg-config --libs --cflags opencv4) +frei0r-run: frei0r-run.c + $(info Build frei0r plugin test run utility) + ${CXX} ${DEBUG_FLAGS} -ggdb -O0 -I../include -o frei0r-run frei0r-run.c ${CVFLAGS} -ldl -test-all-filters: frei0r-test +check-asan: frei0r-run @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) - @find ${PLUGINDIR} -type f -name '*.so' -exec ./frei0r-test -t -v ${HOME}/Downloads/frei0r-all.webm -p {} \; + @find ${PLUGINDIR} -type f -name '*.so' -exec ./frei0r-run -t -v ${HOME}/Downloads/frei0r-all.webm -p {} \; # @$(if $(wildcard frei0r-test),,make test-utils) -scan-plugins: +frei0r-meta: frei0r-meta.c + $(info Build frei0r meta-data parsing utility) + ${CC} -o frei0r-meta -ggdb frei0r-meta.c ${INCLUDES} + +scan-meta: frei0r-meta @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) - @find ${PLUGINDIR} -type f -name '*.so' -exec ./frei0r-info {} \; > tmp.json + @find ${PLUGINDIR} -type f -name '*.so' -exec ./frei0r-meta {} \; > tmp.json @echo "[" > frei0r-plugin-list.json @head -n -1 tmp.json >> frei0r-plugin-list.json @echo "}\n]" >> frei0r-plugin-list.json @@ -34,10 +46,7 @@ generate-metadata: @$(if $(wildcard ${PLUGINDIR}),,>&2 echo "Scan dir not found: ${PLUGINDIR}" && exit 1) sh extract-plugin-info.sh ${EXTENSION} ${PLUGINDIR} -build: - @${CC} -o frei0r-info -ggdb frei0r-info.c ${INCLUDES} - clean: rm -f *.o - rm -f frei0r-info frei0r-test + rm -f frei0r-run frei0r-meta rm -f *.json diff --git a/test/frei0r-info.c b/test/frei0r-meta.c similarity index 100% rename from test/frei0r-info.c rename to test/frei0r-meta.c diff --git a/test/frei0r-test.c b/test/frei0r-run.c similarity index 100% rename from test/frei0r-test.c rename to test/frei0r-run.c