Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Lynne <dev@lynne.ee>
To: Ffmpeg Devel <ffmpeg-devel@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH] checkasm: store and associate contexts with functions and use it for av_tx
Date: Sun, 19 Dec 2021 20:00:23 +0100 (CET)
Message-ID: <MrJ3Ebm--3-2@lynne.ee> (raw)

[-- Attachment #1: Type: text/plain, Size: 1144 bytes --]

checkasm: store and associate contexts with functions and use it for av_tx

The issue is the following:
- checkasm/av_tx.c initializes a context and a function
- check_func() receives the function only and returns NULL
- checkasm/av_tx.c runs again with a different CPU flag and creates a new function and context
- check_func() sees a new function for testing and sets func_ref to the function it first received
- call_ref() and call_new() get called with the same, new context

This means that av_tx contexts had to be compatible with both C and assembly functions.
And so each context difference had to be generated twice and duplicated to keep checkasm
working.

The commit introduces a new *cont in the checkasm function struct, which is associated
with each function. Code that doesn't need an additional context requires no changes,
as we use wrapper macros.

A downside is that there's no way to free contexts until the very end. However, as
checkasm is a testing infrastructure, I think it's reasonable, and we're talking a few
tens of kilobytes of heap memory as we only test a limited number of smaller transforms.

Patch attached.


[-- Attachment #2: 0001-checkasm-store-and-associate-contexts-with-functions.patch --]
[-- Type: text/x-patch, Size: 8034 bytes --]

From 65d655740d75918dc78ba562a6ad682bfa55f480 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Sun, 19 Dec 2021 19:44:40 +0100
Subject: [PATCH] checkasm: store and associate contexts with functions and use
 it for av_tx

The issue is the following:
 - checkasm/av_tx.c initializes a context and a function
 - check_func() receives the function only and returns NULL
 - checkasm/av_tx.c runs again with a different CPU flag and creates a new function and context
 - check_func() sees a new function for testing and sets func_ref to the function it first received
 - call_ref() and call_new() get called with the same, new context

This means that av_tx contexts had to be compatible with both C and assembly functions.
And so each context difference had to be generated twice and duplicated to keep checkasm
working.

The commit introduces a new *cont in the checkasm function struct, which is associated
with each function. Code that doesn't need an additional context requires no changes,
as we use wrapper macros.

A downside is that there's no way to free contexts until the very end. However, as
checkasm is a testing infrastructure, I think it's reasonable, and we're talking a few
tens of kilobytes of heap memory as we only test a limited number of smaller transforms.
---
 tests/checkasm/av_tx.c    | 10 +++++-----
 tests/checkasm/checkasm.c | 21 ++++++++++++---------
 tests/checkasm/checkasm.h | 10 +++++++---
 3 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/tests/checkasm/av_tx.c b/tests/checkasm/av_tx.c
index 178fb61972..afa5dbac72 100644
--- a/tests/checkasm/av_tx.c
+++ b/tests/checkasm/av_tx.c
@@ -58,11 +58,11 @@ static const int check_lens[] = {
                 return;                                                           \
             }                                                                     \
                                                                                   \
-            if (check_func(fn, PREFIX "_%i", len)) {                              \
+            if (check_func_cont(fn, tx, PREFIX "_%i", len)) {                     \
                 num_checks++;                                                     \
                 last_check = len;                                                 \
-                call_ref(tx, out_ref, in, sizeof(DATA_TYPE));                     \
-                call_new(tx, out_new, in, sizeof(DATA_TYPE));                     \
+                call_ref(cont_ref, out_ref, in, sizeof(DATA_TYPE));               \
+                call_new(cont_new, out_new, in, sizeof(DATA_TYPE));               \
                 if (CHECK_EXPRESSION) {                                           \
                     fail();                                                       \
                     break;                                                        \
@@ -70,11 +70,11 @@ static const int check_lens[] = {
                 bench_new(tx, out_new, in, sizeof(DATA_TYPE));                    \
             }                                                                     \
                                                                                   \
-            av_tx_uninit(&tx);                                                    \
+            tx = NULL;                                                            \
             fn = NULL;                                                            \
         }                                                                         \
                                                                                   \
-        av_tx_uninit(&tx);                                                        \
+        tx = NULL;                                                                \
         fn = NULL;                                                                \
                                                                                   \
         if (num_checks == 1)                                                      \
diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c
index 90d080de02..33b7226ff3 100644
--- a/tests/checkasm/checkasm.c
+++ b/tests/checkasm/checkasm.c
@@ -246,6 +246,7 @@ static const struct {
 typedef struct CheckasmFuncVersion {
     struct CheckasmFuncVersion *next;
     void *func;
+    void *cont;
     int ok;
     int cpu;
     CheckasmPerf perf;
@@ -735,12 +736,11 @@ int main(int argc, char *argv[])
 }
 
 /* Decide whether or not the specified function needs to be tested and
- * allocate/initialize data structures if needed. Returns a pointer to a
- * reference function if the function should be tested, otherwise NULL */
-void *checkasm_check_func(void *func, const char *name, ...)
+ * allocate/initialize data structures if needed. Sets *func_ref and *ctx_ref to the
+ * reference function and context if so, otherwise NULL */
+int checkasm_check_func(void *func, void **func_ref, void *cont, void **cont_ref, const char *name, ...)
 {
     char name_buf[256];
-    void *ref = func;
     CheckasmFuncVersion *v;
     int name_length;
     va_list arg;
@@ -750,7 +750,7 @@ void *checkasm_check_func(void *func, const char *name, ...)
     va_end(arg);
 
     if (!func || name_length <= 0 || name_length >= sizeof(name_buf))
-        return NULL;
+        return 0;
 
     state.current_func = get_func(&state.funcs, name_buf);
     state.funcs->color = 1;
@@ -761,10 +761,12 @@ void *checkasm_check_func(void *func, const char *name, ...)
         do {
             /* Only test functions that haven't already been tested */
             if (v->func == func)
-                return NULL;
+                return 0;
 
-            if (v->ok)
-                ref = v->func;
+            if (v->ok) {
+                *func_ref = v->func;
+                *cont_ref = v->cont;
+            }
 
             prev = v;
         } while ((v = v->next));
@@ -773,6 +775,7 @@ void *checkasm_check_func(void *func, const char *name, ...)
     }
 
     v->func = func;
+    v->cont = cont;
     v->ok = 1;
     v->cpu = state.cpu_flag;
     state.current_func_ver = v;
@@ -780,7 +783,7 @@ void *checkasm_check_func(void *func, const char *name, ...)
     if (state.cpu_flag)
         state.num_checked++;
 
-    return ref;
+    return !!(*func_ref);
 }
 
 /* Decide whether or not the current function needs to be benchmarked */
diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h
index 68b0697d3e..e65deabd79 100644
--- a/tests/checkasm/checkasm.h
+++ b/tests/checkasm/checkasm.h
@@ -87,7 +87,7 @@ void checkasm_check_videodsp(void);
 
 struct CheckasmPerf;
 
-void *checkasm_check_func(void *func, const char *name, ...) av_printf_format(2, 3);
+int checkasm_check_func(void *func, void **func_ref, void *cont, void **cont_ref, const char *name, ...) av_printf_format(5, 6);
 int checkasm_bench_func(void);
 void checkasm_fail_func(const char *msg, ...) av_printf_format(1, 2);
 struct CheckasmPerf *checkasm_get_perf_context(void);
@@ -111,11 +111,15 @@ extern AVLFG checkasm_lfg;
 #define rnd() av_lfg_get(&checkasm_lfg)
 
 static av_unused void *func_ref, *func_new;
+static av_unused void *cont_ref, *cont_new;
 
 #define BENCH_RUNS 1000 /* Trade-off between accuracy and speed */
 
-/* Decide whether or not the specified function needs to be tested */
-#define check_func(func, ...) (func_ref = checkasm_check_func((func_new = func), __VA_ARGS__))
+/* Decide whether or not the specified function needs to be tested, returns !0 if so, otherwise 0 */
+#define check_func(func, ...) (checkasm_check_func((func_new = func), &func_ref, NULL, &cont_ref, __VA_ARGS__))
+
+/* Same as above, only takes a function-specific context */
+#define check_func_cont(func, cont, ...) (checkasm_check_func((func_new = func), &func_ref, (cont_new = cont), &cont_ref, __VA_ARGS__))
 
 /* Declare the function prototype. The first argument is the return value, the remaining
  * arguments are the function parameters. Naming parameters is optional. */
-- 
2.34.1


[-- Attachment #3: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

                 reply	other threads:[~2021-12-19 19:00 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=MrJ3Ebm--3-2@lynne.ee \
    --to=dev@lynne.ee \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git