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".