Felipe97/llama-cpp-compiled
01.1k
1#include "testing.h"2 3#include "mtmd-image.h"4#include "mtmd-internal.h"5 6#include <iostream>7#include <stdexcept>8#include <string>9#include <tuple>10#include <utility>11#include <vector>12 13// this test file contains:14// 1. test cases for mtmd helpers15// 2. test cases for internal mtmd components16// internal headers can be included here17 18struct test_registry {19 using fn_t = void (*)(testing &);20 21 struct entry {22 std::string name;23 fn_t fn;24 };25 26 static std::vector<entry> & all() {27 static std::vector<entry> entries;28 return entries;29 }30 31 test_registry(const char * name, fn_t fn) {32 all().push_back({ name, fn });33 }34};35 36#define MAKE_TEST(name) \37 static void name(testing & t); \38 static const test_registry test_registry_ ## name(#name, &name); \39 static void name(testing & t)40 41 42//43// mtmd_image44//45 46MAKE_TEST(test_image_preprocessor_lfm2) {47 clip_hparams hparams;48 hparams.patch_size = 16;49 hparams.n_merge = 2;50 hparams.set_limit_image_tokens(64, 256);51 52 // { image size, expected tiling }53 const std::vector<std::pair<clip_image_size, bool>> cases = {54 { { 704, 704 }, false },55 // 720 / (patch_size * n_merge) is exactly 22.5, so this only matches HF56 // if round_by_factor rounds half to even (22) instead of away from zero (23)57 { { 720, 720 }, false },58 { { 736, 736 }, true },59 { { 1024, 977 }, true },60 { { 1056, 384 }, false },61 };62 63 for (const auto & [size, expected] : cases) {64 const bool actual = mtmd_image_preprocessor_lfm2::should_tile(hparams, size);65 66 t.assert_equal(67 "tiling for " + std::to_string(size.width) + "x" + std::to_string(size.height),68 std::string(expected ? "tiled" : "single"),69 std::string(actual ? "tiled" : "single"));70 }71}72 73//74// mtmd temporal merge75//76 77MAKE_TEST(test_temporal_merge_grouping) {78 std::vector<mtmd::bitmap_ptr> pool; // keeps the bitmaps alive until the end of the test79 80 // spec chars:81 // v = video frame, w = video frame of another size, a = audio, i = plain image, t = text82 auto make_parts = [&pool](const std::string & spec) {83 std::vector<mtmd_internal_part> parts;84 for (char c : spec) {85 if (c == 't') {86 parts.push_back({ "hello", nullptr });87 continue;88 }89 mtmd_bitmap * bm = nullptr;90 switch (c) {91 case 'v': bm = mtmd_bitmap_init(100, 100, nullptr); break;92 case 'w': bm = mtmd_bitmap_init(200, 200, nullptr); break;93 case 'a': bm = mtmd_bitmap_init_from_audio(100, nullptr); break;94 case 'i': bm = mtmd_bitmap_init(100, 100, nullptr); break;95 default: throw std::runtime_error(std::string("unknown spec char: ") + c);96 }97 mtmd_bitmap_set_mergeable(bm, c != 'i');98 pool.emplace_back(bm);99 parts.push_back({ "", bm });100 }101 return parts;102 };103 104 // { parts, n_merge, expected size of each group }105 const std::vector<std::tuple<std::string, int, std::string>> cases = {106 { "vv", 2, "2" },107 { "vvv", 2, "21" },108 { "vvvv", 2, "22" },109 { "vvi", 2, "21" },110 { "tvvt", 2, "2" },111 { "vtv", 2, "11" }, // text in between breaks the merge112 { "vw", 2, "11" }, // different sizes cannot be merged113 { "aa", 2, "11" }, // audio is never merged114 { "ii", 2, "11" }, // two unrelated images must stay separated115 { "iv", 2, "11" },116 { "vi", 2, "11" },117 { "vv", 1, "11" }, // model without temporal merge118 };119 120 for (const auto & [spec, n_merge, expected] : cases) {121 auto parts = make_parts(spec);122 auto groups = mtmd_group_mergeable_bitmaps(parts, n_merge);123 124 std::string actual;125 for (const auto & group : groups) {126 actual += std::to_string(group.size());127 }128 129 const std::string name = "\"" + spec + "\" with n_merge=" + std::to_string(n_merge);130 t.assert_equal("groups for " + name, expected, actual);131 132 size_t n_bitmap_parts = 0;133 for (const auto & p : parts) {134 n_bitmap_parts += p.bitmap != nullptr ? 1 : 0;135 }136 t.assert_equal("remaining bitmap parts for " + name, groups.size(), n_bitmap_parts);137 }138}139 140//141// main142//143 144int main(int argc, char ** argv) {145 testing t(std::cout);146 t.verbose = true;147 148 // usage: test-mtmd-impl [filter_regex]149 for (int i = 1; i < argc; i++) {150 t.set_filter(argv[i]);151 }152 153 for (const auto & e : test_registry::all()) {154 t.test(e.name, e.fn);155 }156 157 return t.summary();158}159 