From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <ffmpeg-devel-bounces@ffmpeg.org>
Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100])
	by master.gitmailbox.com (Postfix) with ESMTPS id 6992E4CAC1
	for <ffmpegdev@gitmailbox.com>; Sat, 12 Apr 2025 15:12:53 +0000 (UTC)
Received: from [127.0.1.1] (localhost [127.0.0.1])
	by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2443A68B1F0;
	Sat, 12 Apr 2025 18:12:30 +0300 (EEST)
Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com
 [209.85.214.177])
 by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EB9CB68B148
 for <ffmpeg-devel@ffmpeg.org>; Sat, 12 Apr 2025 18:12:22 +0300 (EEST)
Received: by mail-pl1-f177.google.com with SMTP id
 d9443c01a7336-2240b4de12bso40832645ad.2
 for <ffmpeg-devel@ffmpeg.org>; Sat, 12 Apr 2025 08:12:22 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1744470741; x=1745075541; darn=ffmpeg.org;
 h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date
 :references:in-reply-to:message-id:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=E9eQIocyZJ8rfXxmuCWZX7agw4nB49IfEcyrj4ZuGwE=;
 b=lZKeec/cpjMULlYdllxFqRahnNixrdxayw65cUYv8A0R2TfQ61ox0Z20j8qMAZyChU
 aITDkb8UILGE8ImOII6DTUM6UvncnyABiaQilxmXvB5OFbH+gHQiwB2Mzf5qHiS/8EOL
 IyO3+Pwlcj4s25Ia0L7rb6xvkGgUzkckRjfRDq/bdcBRrTvcJxugyZ/2JKt7heX0hZrs
 Gn/77ffNaqhzSkMkyJ8UlaCyWW0uhl5/aH4z7G1kFinCP04elPnwYzXnXWwtKZef6bZm
 WTC8GTojGNKH49URq8KzeSnMwkPSv5a3A4ezMvCtVSb1/nSB/QAkcoz+w1Ces09vJ9Y+
 4ydA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744470741; x=1745075541;
 h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date
 :references:in-reply-to:message-id:from:x-gm-message-state:from:to
 :cc:subject:date:message-id:reply-to;
 bh=E9eQIocyZJ8rfXxmuCWZX7agw4nB49IfEcyrj4ZuGwE=;
 b=f+aK1YwLHDD53rz4+aAETLRDQlgN1gkNKpIFHXAzJPgi4gNkFOMIJPU3uruUudZrn0
 tTkZOr1w1iuP8G/7a6t1cst2QKBA11h+Yn8Ac9Gk+K7r2eWeCrDJuP5yPAkT+95f6k+p
 mzTpCKuBJrKa9qM2971gaz1jHHJxW4XZ7lHFIwhg9Wo6PyiaY1l7yaFonNd/dYnXbswf
 kvEDVMYbvZc7lFkaKSvcEPti8G+DSL8FBZZ31f/tOuy7nrNU7tzTR4ae8p2ixTpI3HK3
 3DwWNMC1n5+vxJOaUj//QsMI20fc0m7xee35/rhHILGXY5bi1CbjwRGqVYJzo3HyiPQJ
 3hQA==
X-Gm-Message-State: AOJu0Yx2NGj6Zi1S3pdKn2ELQGHIgAE58taA8TWg5wAdDfyHBHJHYC6+
 /+/PWfB3/mmC9Vn0s7yAMeZLrrwSbRIP8APQsZbicI+3d9kEAxe8QtyL0A==
X-Gm-Gg: ASbGnctyy+vLKNCkyIHa8UzrOELB68GCqiFfGiNaltw6HG49XcPg18SYqfLZZcekmOO
 w8NV38iSlU3CEeQxim3osxaf7KlGknJXpFuy5fvArG+XdXi7pmMgCbzSUejlILq1j7/Wc0B1SYA
 Fw7Uq6dk5TXWqyqyoL6t2j6IZoZBfHAFPyrWie2W+77jYmgvafHHRVhNe2VWIMNDHnpn4JXSNTp
 kqv/9acX5/esbVKVSsuHFiqKADCtdhUsxrVi1390s8hfsqaqT34udsByBkypBT3OF7Y3or6B4Yz
 Ko6Y1ydHIr4Ui9ir1Zrr0RLQkH/lbzWo2Fq/IrRYW56+MwkfwNDoku+fop8=
X-Google-Smtp-Source: AGHT+IHPK9uH/JqHrgS3t0t8FmmUSgioh7KeV2xyDc8aQwypzG7Nre3q5cMdxvv0Ed0J2KaHVxCgKQ==
X-Received: by 2002:a17:902:d2c2:b0:227:e6fe:2908 with SMTP id
 d9443c01a7336-22bea50bd27mr88638935ad.48.1744470740855; 
 Sat, 12 Apr 2025 08:12:20 -0700 (PDT)
Received: from [127.0.0.1] (master.gitmailbox.com. [34.83.118.50])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-22ac7cc9202sm68601615ad.211.2025.04.12.08.12.20
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Sat, 12 Apr 2025 08:12:20 -0700 (PDT)
From: softworkz <ffmpegagent@gmail.com>
X-Google-Original-From: softworkz <softworkz@hotmail.com>
Message-Id: <98b58ebfb4c672ddc41ac9f87f5a611e2ae2e8d9.1744470718.git.ffmpegagent@gmail.com>
In-Reply-To: <pull.64.ffstaging.FFmpeg.1744470718.ffmpegagent@gmail.com>
References: <pull.64.ffstaging.FFmpeg.1744470718.ffmpegagent@gmail.com>
Date: Sat, 12 Apr 2025 15:11:58 +0000
Fcc: Sent
MIME-Version: 1.0
To: ffmpeg-devel@ffmpeg.org
Subject: [FFmpeg-devel] [PATCH 3/3] tests/dict2: Add tests and benchmark for
 AVDictionary2
X-BeenThere: ffmpeg-devel@ffmpeg.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
Reply-To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Cc: softworkz <softworkz@hotmail.com>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: ffmpeg-devel-bounces@ffmpeg.org
Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
Archived-At: <https://master.gitmailbox.com/ffmpegdev/98b58ebfb4c672ddc41ac9f87f5a611e2ae2e8d9.1744470718.git.ffmpegagent@gmail.com/>
List-Archive: <https://master.gitmailbox.com/ffmpegdev/>
List-Post: <mailto:ffmpegdev@gitmailbox.com>

From: softworkz <softworkz@hotmail.com>

Signed-off-by: softworkz <softworkz@hotmail.com>
---
 libavutil/tests/dict2.c    | 185 +++++++++++++++++++++++++++++
 tests/api/Makefile         |   1 +
 tests/api/api-dict2-test.c | 122 +++++++++++++++++++
 tests/fate/api.mak         |  15 +++
 tools/Makefile             |   2 +-
 tools/dict2_benchmark.c    | 237 +++++++++++++++++++++++++++++++++++++
 6 files changed, 561 insertions(+), 1 deletion(-)
 create mode 100644 libavutil/tests/dict2.c
 create mode 100644 tests/api/api-dict2-test.c
 create mode 100644 tools/dict2_benchmark.c

diff --git a/libavutil/tests/dict2.c b/libavutil/tests/dict2.c
new file mode 100644
index 0000000000..31c9f568f6
--- /dev/null
+++ b/libavutil/tests/dict2.c
@@ -0,0 +1,185 @@
+/*
+ * AVDictionary2 test utility
+ * This file is part of FFmpeg.
+ */
+
+#include "libavutil/dict2.h"
+#include "libavutil/dict.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+static void basic_functionality_test(void)
+{
+    printf("\n=== Basic Functionality Test ===\n");
+    
+    AVDictionary2 *dict = NULL;
+    AVDictionaryEntry2 *entry;
+    int ret;
+    
+    // Test setting keys
+    ret = av_dict2_set(&dict, "key1", "value1", 0);
+    printf("Adding key1: %s\n", ret >= 0 ? "OK" : "FAILED");
+    av_assert0(ret >= 0);
+    
+    ret = av_dict2_set(&dict, "key2", "value2", 0);
+    printf("Adding key2: %s\n", ret >= 0 ? "OK" : "FAILED");
+    av_assert0(ret >= 0);
+    
+    // Test lookup
+    entry = av_dict2_get(dict, "key1", NULL, 0);
+    printf("Lookup key1: %s (value: %s)\n", 
+           entry ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value1"));
+    
+    // Test count
+    int count = av_dict2_count(dict);
+    printf("Dictionary count: %d (expected 2)\n", count);
+    av_assert0(count == 2);
+    
+    // Test iteration
+    printf("Dictionary contents:\n");
+    const AVDictionaryEntry2 *iter = NULL;
+    while ((iter = av_dict2_iterate(dict, iter))) {
+        printf("  %s: %s\n", iter->key, iter->value);
+    }
+    
+    // Free dictionary
+    av_dict2_free(&dict);
+    printf("Dictionary freed successfully\n");
+}
+
+static void overwrite_test(void)
+{
+    printf("\n=== Overwrite Test ===\n");
+    
+    AVDictionary2 *dict = NULL;
+    AVDictionaryEntry2 *entry;
+    
+    // Test normal overwrite
+    av_dict2_set(&dict, "key", "value1", 0);
+    av_dict2_set(&dict, "key", "value2", 0);
+    
+    entry = av_dict2_get(dict, "key", NULL, 0);
+    printf("Overwrite test: %s (value: %s, expected: value2)\n", 
+           entry && !strcmp(entry->value, "value2") ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value2"));
+    
+    // Test DONT_OVERWRITE flag
+    av_dict2_set(&dict, "key", "value3", AV_DICT2_DONT_OVERWRITE);
+    
+    entry = av_dict2_get(dict, "key", NULL, 0);
+    printf("DONT_OVERWRITE flag test: %s (value: %s, expected: value2)\n", 
+           entry && !strcmp(entry->value, "value2") ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value2"));
+    
+    av_dict2_free(&dict);
+}
+
+static void case_sensitivity_test(void)
+{
+    printf("\n=== Case Sensitivity Test ===\n");
+    
+    // Test case-sensitive dictionary with AV_DICT2_MATCH_CASE flag
+    AVDictionary2 *dict1 = NULL;
+    av_dict2_set(&dict1, "Key", "value1", AV_DICT2_MATCH_CASE);
+    
+    AVDictionaryEntry2 *entry1 = av_dict2_get(dict1, "key", NULL, AV_DICT2_MATCH_CASE);
+    printf("Case-sensitive lookup: %s (expected NULL)\n", 
+           entry1 ? "FAILED" : "OK");
+    av_assert0(entry1 == NULL);
+    
+    // Test case-insensitive dictionary (default behavior)
+    AVDictionary2 *dict2 = NULL;
+    av_dict2_set(&dict2, "Key", "value1", 0); 
+    
+    AVDictionaryEntry2 *entry2 = av_dict2_get(dict2, "key", NULL, 0);
+    printf("Case-insensitive lookup: %s (value: %s)\n", 
+           entry2 ? "OK" : "FAILED",
+           entry2 ? entry2->value : "NULL");
+    av_assert0(entry2 && !strcmp(entry2->value, "value1"));
+    
+    av_dict2_free(&dict1);
+    av_dict2_free(&dict2);
+}
+
+static void stress_test(void)
+{
+    printf("\n=== Stress Test ===\n");
+    
+    AVDictionary2 *dict = NULL;
+    char key[32], value[32];
+    int i, count, lookup_successful = 0;
+    int64_t start_time, elapsed;
+    
+    // Create a large number of entries
+    const int num_entries = 10000;
+    printf("Creating %d entries...\n", num_entries);
+    
+    start_time = av_gettime();
+    for (i = 0; i < num_entries; i++) {
+        sprintf(key, "key%d", i);
+        sprintf(value, "value%d", i);
+        av_dict2_set(&dict, key, value, 0);
+    }
+    elapsed = av_gettime() - start_time;
+    printf("Insertion time: %" PRId64 " us (%.2f us per entry)\n", 
+           elapsed, (double)elapsed / num_entries);
+    
+    // Test lookup of all keys
+    printf("Looking up all keys...\n");
+    start_time = av_gettime();
+    for (i = 0; i < num_entries; i++) {
+        sprintf(key, "key%d", i);
+        AVDictionaryEntry2 *entry = av_dict2_get(dict, key, NULL, 0);
+        if (entry) lookup_successful++;
+    }
+    elapsed = av_gettime() - start_time;
+    printf("Lookup time: %" PRId64 " us (%.2f us per lookup)\n", 
+           elapsed, (double)elapsed / num_entries);
+    printf("Found %d of %d entries\n", lookup_successful, num_entries);
+    av_assert0(lookup_successful == num_entries);
+    
+    // Check count
+    count = av_dict2_count(dict);
+    printf("Dictionary count: %d (expected %d)\n", count, num_entries);
+    av_assert0(count == num_entries);
+    
+    // Free dictionary and measure cleanup time
+    start_time = av_gettime();
+    av_dict2_free(&dict);
+    elapsed = av_gettime() - start_time;
+    printf("Cleanup time: %" PRId64 " us\n", elapsed);
+    printf("Stress test completed successfully\n");
+}
+
+int main(int argc, char **argv)
+{
+    printf("AVDictionary2 Test Suite\n");
+    printf("========================\n");
+    
+    // Check if specific test is requested
+    int run_stress = 0;
+    if (argc >= 2 && !strcmp(argv[1], "stress")) {
+        run_stress = 1;
+    }
+    
+    // Always run basic tests
+    basic_functionality_test();
+    overwrite_test();
+    case_sensitivity_test();
+    
+    // Run stress test if requested
+    if (run_stress) {
+        stress_test();
+    }
+
+    printf("\nAll tests PASSED!\n");
+    return 0;
+}
diff --git a/tests/api/Makefile b/tests/api/Makefile
index c96e636756..4d069f7bae 100644
--- a/tests/api/Makefile
+++ b/tests/api/Makefile
@@ -2,6 +2,7 @@ APITESTPROGS-$(call ENCDEC, FLAC, FLAC) += api-flac
 APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264
 APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264-slice
 APITESTPROGS-yes += api-seek
+APITESTPROGS-yes += api-dict2
 APITESTPROGS-$(call DEMDEC, H263, H263) += api-band
 APITESTPROGS-$(HAVE_THREADS) += api-threadmessage
 APITESTPROGS += $(APITESTPROGS-yes)
diff --git a/tests/api/api-dict2-test.c b/tests/api/api-dict2-test.c
new file mode 100644
index 0000000000..a120a3488c
--- /dev/null
+++ b/tests/api/api-dict2-test.c
@@ -0,0 +1,122 @@
+/*
+ * AVDictionary2 test utility
+ * This file is part of FFmpeg.
+ */
+
+#include "libavutil/dict2.h"
+#include "libavutil/dict.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void basic_functionality_test(void)
+{
+    printf("\n=== Basic Functionality Test ===\n");
+
+    AVDictionary2 *dict = NULL;
+    AVDictionaryEntry2 *entry;
+    int ret;
+
+    // Test setting keys
+    ret = av_dict2_set(&dict, "key1", "value1", 0);
+    printf("Adding key1: %s\n", ret >= 0 ? "OK" : "FAILED");
+    av_assert0(ret >= 0);
+
+    ret = av_dict2_set(&dict, "key2", "value2", 0);
+    printf("Adding key2: %s\n", ret >= 0 ? "OK" : "FAILED");
+    av_assert0(ret >= 0);
+
+    // Test lookup
+    entry = av_dict2_get(dict, "key1", NULL, 0);
+    printf("Lookup key1: %s (value: %s)\n",
+           entry ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value1"));
+
+    // Test count
+    int count = av_dict2_count(dict);
+    printf("Dictionary count: %d (expected 2)\n", count);
+    av_assert0(count == 2);
+
+    // Test iteration
+    printf("Dictionary contents:\n");
+    const AVDictionaryEntry2 *iter = NULL;
+    while ((iter = av_dict2_iterate(dict, iter))) {
+        printf("  %s: %s\n", iter->key, iter->value);
+    }
+
+    // Free dictionary
+    av_dict2_free(&dict);
+    printf("Dictionary freed successfully\n");
+}
+
+static void overwrite_test(void)
+{
+    printf("\n=== Overwrite Test ===\n");
+
+    AVDictionary2 *dict = NULL;
+    AVDictionaryEntry2 *entry;
+
+    // Test normal overwrite
+    av_dict2_set(&dict, "key", "value1", 0);
+    av_dict2_set(&dict, "key", "value2", 0);
+
+    entry = av_dict2_get(dict, "key", NULL, 0);
+    printf("Overwrite test: %s (value: %s expected: value2)\n",
+           entry && !strcmp(entry->value, "value2") ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value2"));
+
+    // Test DONT_OVERWRITE flag
+    av_dict2_set(&dict, "key", "value3", AV_DICT2_DONT_OVERWRITE);
+
+    entry = av_dict2_get(dict, "key", NULL, 0);
+    printf("DONT_OVERWRITE flag test: %s (value: %s expected: value2)\n",
+           entry && !strcmp(entry->value, "value2") ? "OK" : "FAILED",
+           entry ? entry->value : "NULL");
+    av_assert0(entry && !strcmp(entry->value, "value2"));
+
+    av_dict2_free(&dict);
+}
+
+static void case_sensitivity_test(void)
+{
+    printf("\n=== Case Sensitivity Test ===\n");
+
+    // Test case-sensitive dictionary with AV_DICT2_MATCH_CASE flag
+    AVDictionary2 *dict1 = NULL;
+    av_dict2_set(&dict1, "Key", "value1", AV_DICT2_MATCH_CASE);
+
+    AVDictionaryEntry2 *entry1 = av_dict2_get(dict1, "key", NULL, AV_DICT2_MATCH_CASE);
+    printf("Case-sensitive lookup: %s (expected NULL)\n",
+           entry1 ? "FAILED" : "OK");
+    av_assert0(entry1 == NULL);
+
+    // Test case-insensitive dictionary (default behavior)
+    AVDictionary2 *dict2 = NULL;
+    av_dict2_set(&dict2, "Key", "value1", 0);
+
+    AVDictionaryEntry2 *entry2 = av_dict2_get(dict2, "key", NULL, 0);
+    printf("Case-insensitive lookup: %s (value: %s)\n",
+           entry2 ? "OK" : "FAILED",
+           entry2 ? entry2->value : "NULL");
+    av_assert0(entry2 && !strcmp(entry2->value, "value1"));
+
+    av_dict2_free(&dict1);
+    av_dict2_free(&dict2);
+}
+
+int main(void)
+{
+    printf("AVDictionary2 Test Suite\n");
+    printf("========================\n");
+
+    basic_functionality_test();
+    overwrite_test();
+    case_sensitivity_test();
+
+    printf("\nAll tests PASSED!\n");
+    return 0;
+}
diff --git a/tests/fate/api.mak b/tests/fate/api.mak
index d2868e57ac..18219eab1d 100644
--- a/tests/fate/api.mak
+++ b/tests/fate/api.mak
@@ -27,6 +27,21 @@ fate-api-threadmessage: $(APITESTSDIR)/api-threadmessage-test$(EXESUF)
 fate-api-threadmessage: CMD = run $(APITESTSDIR)/api-threadmessage-test$(EXESUF) 3 10 30 50 2 20 40
 fate-api-threadmessage: CMP = null
 
+FATE_API-yes += fate-api-dict2
+fate-api-dict2: $(APITESTSDIR)/api-dict2-test$(EXESUF)
+fate-api-dict2: CMD = run $(APITESTSDIR)/api-dict2-test$(EXESUF)
+fate-api-dict2: CMP = null
+
+# Dict2 implementation tests
+FATE_DICT2 = fate-dict2-basic fate-dict2-stress
+FATE_AVUTIL += $(FATE_DICT2)
+
+fate-dict2-basic: libavutil/tests/dict2$(EXESUF)
+fate-dict2-basic: CMD = run libavutil/tests/dict2 basic
+
+fate-dict2-stress: libavutil/tests/dict2$(EXESUF)
+fate-dict2-stress: CMD = run libavutil/tests/dict2 stress
+
 FATE_API_SAMPLES-$(CONFIG_AVFORMAT) += $(FATE_API_SAMPLES_LIBAVFORMAT-yes)
 
 ifdef SAMPLES
diff --git a/tools/Makefile b/tools/Makefile
index 7ae6e3cb75..d0a5c45c80 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -1,4 +1,4 @@
-TOOLS = enc_recon_frame_test enum_options qt-faststart scale_slice_test trasher uncoded_frame
+TOOLS = dict2_benchmark enc_recon_frame_test enum_options qt-faststart scale_slice_test trasher uncoded_frame
 TOOLS-$(CONFIG_LIBMYSOFA) += sofa2wavs
 TOOLS-$(CONFIG_ZLIB) += cws2fws
 
diff --git a/tools/dict2_benchmark.c b/tools/dict2_benchmark.c
new file mode 100644
index 0000000000..bdf34440b9
--- /dev/null
+++ b/tools/dict2_benchmark.c
@@ -0,0 +1,237 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * AVDictionary vs AVDictionary2 Benchmark
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "libavutil/dict.h"
+#include "libavutil/dict2.h"
+#include "libavutil/time.h"
+
+#define RAND_STR_LEN 16
+#define TEST_ITERATIONS 5000
+
+/* Generate random string */
+static void gen_random_str(char *s, int len) {
+    static const char alphanum[] =
+        "0123456789"
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrstuvwxyz";
+    int i;
+
+    for (i = 0; i < len - 1; i++) {
+        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
+    }
+    s[len - 1] = '\0';
+}
+
+/* Fill a dictionary with random key-value pairs */
+static void fill_dict(AVDictionary **dict, int count) {
+    int i;
+    char key[RAND_STR_LEN];
+    char val[RAND_STR_LEN];
+
+    for (i = 0; i < count; i++) {
+        gen_random_str(key, RAND_STR_LEN);
+        gen_random_str(val, RAND_STR_LEN);
+        av_dict_set(dict, key, val, 0);
+    }
+}
+
+/* Fill a dictionary2 with random key-value pairs */
+static void fill_dict2(AVDictionary2 **dict, int count) {
+    int i;
+    char key[RAND_STR_LEN];
+    char val[RAND_STR_LEN];
+
+    for (i = 0; i < count; i++) {
+        gen_random_str(key, RAND_STR_LEN);
+        gen_random_str(val, RAND_STR_LEN);
+        av_dict2_set(dict, key, val, 0);
+    }
+}
+
+/* Generate lookup keys: some existing and some new */
+static char **gen_lookup_keys(int count, AVDictionary *dict, int hit_ratio_percent) {
+    int i, hits = count * hit_ratio_percent / 100;
+    char **keys = malloc(count * sizeof(char *));
+    if (!keys) return NULL;
+
+    // First add some keys that exist in the dictionary
+    AVDictionaryEntry *entry = NULL;
+    for (i = 0; i < hits && i < count; i++) {
+        entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX);
+        if (!entry) break; // Not enough entries
+
+        keys[i] = malloc(RAND_STR_LEN);
+        if (!keys[i]) {
+            while (--i >= 0) free(keys[i]);
+            free(keys);
+            return NULL;
+        }
+        strcpy(keys[i], entry->key);
+    }
+
+    // Fill the rest with random keys (likely misses)
+    for (; i < count; i++) {
+        keys[i] = malloc(RAND_STR_LEN);
+        if (!keys[i]) {
+            while (--i >= 0) free(keys[i]);
+            free(keys);
+            return NULL;
+        }
+        gen_random_str(keys[i], RAND_STR_LEN);
+    }
+
+    return keys;
+}
+
+/* Free lookup keys */
+static void free_lookup_keys(char **keys, int count) {
+    int i;
+    for (i = 0; i < count; i++) {
+        free(keys[i]);
+    }
+    free(keys);
+}
+
+int main(int argc, char *argv[])
+{
+    int count = 1000; // Default dictionary size
+    double time_start, time_end, time_dict, time_dict2;
+
+    // Parse command line for count
+    if (argc > 1) {
+        count = atoi(argv[1]);
+        if (count <= 0) count = 1000;
+    }
+
+    printf("Benchmarking AVDictionary vs AVDictionary2 with %d entries\n\n", count);
+
+    srand(1234); // Fixed seed for reproducibility
+
+    // Setup dictionaries for insertion test
+    AVDictionary *dict1 = NULL;
+    AVDictionary2 *dict2 = NULL;
+
+    // Benchmark 1: Insertion
+    printf("1. Insertion Performance:\n");
+
+    time_start = av_gettime_relative() / 1000.0;
+    fill_dict(&dict1, count);
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict = time_end - time_start;
+    printf("   AVDictionary:  %.3f ms\n", time_dict);
+
+    time_start = av_gettime_relative() / 1000.0;
+    fill_dict2(&dict2, count);
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict2 = time_end - time_start;
+    printf("   AVDictionary2: %.3f ms (%.1f%% of original time)\n", 
+           time_dict2, time_dict2*100.0/time_dict);
+
+    // Benchmark 2: Lookup (existing keys - 100% hit rate)
+    printf("\n2. Lookup Performance (100%% existing keys):\n");
+
+    char **lookup_keys = gen_lookup_keys(TEST_ITERATIONS, dict1, 100);
+    if (!lookup_keys) {
+        fprintf(stderr, "Failed to generate lookup keys\n");
+        return 1;
+    }
+
+    time_start = av_gettime_relative() / 1000.0;
+    for (int i = 0; i < TEST_ITERATIONS; i++) {
+        av_dict_get(dict1, lookup_keys[i], NULL, 0);
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict = time_end - time_start;
+    printf("   AVDictionary:  %.3f ms\n", time_dict);
+
+    time_start = av_gettime_relative() / 1000.0;
+    for (int i = 0; i < TEST_ITERATIONS; i++) {
+        av_dict2_get(dict2, lookup_keys[i], NULL, 0);
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict2 = time_end - time_start;
+    printf("   AVDictionary2: %.3f ms (%.1f%% of original time)\n", 
+           time_dict2, time_dict2*100.0/time_dict);
+
+    free_lookup_keys(lookup_keys, TEST_ITERATIONS);
+
+    // Benchmark 3: Lookup (mixed keys - 50% hit rate)
+    printf("\n3. Lookup Performance (50%% existing keys):\n");
+
+    lookup_keys = gen_lookup_keys(TEST_ITERATIONS, dict1, 50);
+    if (!lookup_keys) {
+        fprintf(stderr, "Failed to generate lookup keys\n");
+        return 1;
+    }
+
+    time_start = av_gettime_relative() / 1000.0;
+    for (int i = 0; i < TEST_ITERATIONS; i++) {
+        av_dict_get(dict1, lookup_keys[i], NULL, 0);
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict = time_end - time_start;
+    printf("   AVDictionary:  %.3f ms\n", time_dict);
+
+    time_start = av_gettime_relative() / 1000.0;
+    for (int i = 0; i < TEST_ITERATIONS; i++) {
+        av_dict2_get(dict2, lookup_keys[i], NULL, 0);
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict2 = time_end - time_start;
+    printf("   AVDictionary2: %.3f ms (%.1f%% of original time)\n", 
+           time_dict2, time_dict2*100.0/time_dict);
+
+    free_lookup_keys(lookup_keys, TEST_ITERATIONS);
+
+    // Benchmark 4: Iteration
+    printf("\n4. Iteration Performance:\n");
+
+    time_start = av_gettime_relative() / 1000.0;
+    AVDictionaryEntry *entry = NULL;
+    while ((entry = av_dict_get(dict1, "", entry, AV_DICT_IGNORE_SUFFIX))) {
+        // Just iterate
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict = time_end - time_start;
+    printf("   AVDictionary:  %.3f ms\n", time_dict);
+
+    time_start = av_gettime_relative() / 1000.0;
+    const AVDictionaryEntry2 *entry2 = NULL;
+    while ((entry2 = av_dict2_iterate(dict2, entry2))) {
+        // Just iterate
+    }
+    time_end = av_gettime_relative() / 1000.0;
+    time_dict2 = time_end - time_start;
+    printf("   AVDictionary2: %.3f ms (%.1f%% of original time)\n", 
+           time_dict2, time_dict2*100.0/time_dict);
+
+    // Cleanup
+    av_dict_free(&dict1);
+    av_dict2_free(&dict2);
+
+    printf("\nBenchmark completed successfully\n");
+    return 0;
+}
-- 
ffmpeg-codebot
_______________________________________________
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".