• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <cstdlib>
13 #include <new>
14 #include <tuple>
15 
16 #include "config/aom_config.h"
17 #include "config/av1_rtcd.h"
18 
19 #include "aom/aom_codec.h"
20 #include "aom/aom_integer.h"
21 #include "aom_mem/aom_mem.h"
22 #include "aom_ports/aom_timer.h"
23 #include "aom_ports/mem.h"
24 #include "test/acm_random.h"
25 #include "av1/encoder/palette.h"
26 #include "test/register_state_check.h"
27 #include "test/util.h"
28 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
29 
30 namespace AV1Kmeans {
31 typedef void (*av1_calc_indices_dim1_func)(const int *data,
32                                            const int *centroids,
33                                            uint8_t *indices, int n, int k);
34 typedef void (*av1_calc_indices_dim2_func)(const int *data,
35                                            const int *centroids,
36                                            uint8_t *indices, int n, int k);
37 
38 typedef std::tuple<av1_calc_indices_dim1_func, BLOCK_SIZE>
39     av1_calc_indices_dim1Param;
40 
41 typedef std::tuple<av1_calc_indices_dim2_func, BLOCK_SIZE>
42     av1_calc_indices_dim2Param;
43 
44 class AV1KmeansTest1
45     : public ::testing::TestWithParam<av1_calc_indices_dim1Param> {
46  public:
47   ~AV1KmeansTest1();
48   void SetUp();
49 
50   void TearDown();
51 
52  protected:
53   void RunCheckOutput(av1_calc_indices_dim1_func test_impl, BLOCK_SIZE bsize,
54                       int centroids);
55   void RunSpeedTest(av1_calc_indices_dim1_func test_impl, BLOCK_SIZE bsize,
56                     int centroids);
CheckResult(int n)57   bool CheckResult(int n) {
58     for (int idx = 0; idx < n; ++idx) {
59       if (indices1_[idx] != indices2_[idx]) {
60         printf("%d ", idx);
61         printf("%d != %d ", indices1_[idx], indices2_[idx]);
62         return false;
63       }
64     }
65     return true;
66   }
67 
68   libaom_test::ACMRandom rnd_;
69   int data_[4096];
70   int centroids_[8];
71   uint8_t indices1_[4096];
72   uint8_t indices2_[4096];
73 };
74 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1KmeansTest1);
75 
~AV1KmeansTest1()76 AV1KmeansTest1::~AV1KmeansTest1() { ; }
77 
SetUp()78 void AV1KmeansTest1::SetUp() {
79   rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
80   for (int i = 0; i < 4096; ++i) {
81     data_[i] = (int)rnd_.Rand8() << 4;
82   }
83   for (int i = 0; i < 8; i++) {
84     centroids_[i] = (int)rnd_.Rand8() << 4;
85   }
86 }
87 
TearDown()88 void AV1KmeansTest1::TearDown() {}
89 
RunCheckOutput(av1_calc_indices_dim1_func test_impl,BLOCK_SIZE bsize,int k)90 void AV1KmeansTest1::RunCheckOutput(av1_calc_indices_dim1_func test_impl,
91                                     BLOCK_SIZE bsize, int k) {
92   const int w = block_size_wide[bsize];
93   const int h = block_size_high[bsize];
94   const int n = w * h;
95   av1_calc_indices_dim1_c(data_, centroids_, indices1_, n, k);
96   test_impl(data_, centroids_, indices2_, n, k);
97 
98   ASSERT_EQ(CheckResult(n), true)
99       << " block " << bsize << " index " << n << " Centroids " << k;
100 }
101 
RunSpeedTest(av1_calc_indices_dim1_func test_impl,BLOCK_SIZE bsize,int k)102 void AV1KmeansTest1::RunSpeedTest(av1_calc_indices_dim1_func test_impl,
103                                   BLOCK_SIZE bsize, int k) {
104   const int w = block_size_wide[bsize];
105   const int h = block_size_high[bsize];
106   const int n = w * h;
107   const int num_loops = 1000000000 / n;
108 
109   av1_calc_indices_dim1_func funcs[2] = { av1_calc_indices_dim1_c, test_impl };
110   double elapsed_time[2] = { 0 };
111   for (int i = 0; i < 2; ++i) {
112     aom_usec_timer timer;
113     aom_usec_timer_start(&timer);
114     av1_calc_indices_dim1_func func = funcs[i];
115     for (int j = 0; j < num_loops; ++j) {
116       func(data_, centroids_, indices1_, n, k);
117     }
118     aom_usec_timer_mark(&timer);
119     double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
120     elapsed_time[i] = 1000.0 * time / num_loops;
121   }
122   printf("av1_calc_indices_dim1 indices= %d centroids=%d: %7.2f/%7.2fns", n, k,
123          elapsed_time[0], elapsed_time[1]);
124   printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
125 }
126 
TEST_P(AV1KmeansTest1,CheckOutput)127 TEST_P(AV1KmeansTest1, CheckOutput) {
128   // centroids = 2..8
129   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 2);
130   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 3);
131   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 4);
132   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 5);
133   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 6);
134   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 7);
135   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 8);
136 }
137 
TEST_P(AV1KmeansTest1,DISABLED_Speed)138 TEST_P(AV1KmeansTest1, DISABLED_Speed) {
139   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 2);
140   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 3);
141   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 4);
142   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 5);
143   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 6);
144   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 7);
145   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 8);
146 }
147 
148 class AV1KmeansTest2
149     : public ::testing::TestWithParam<av1_calc_indices_dim2Param> {
150  public:
151   ~AV1KmeansTest2();
152   void SetUp();
153 
154   void TearDown();
155 
156  protected:
157   void RunCheckOutput(av1_calc_indices_dim2_func test_impl, BLOCK_SIZE bsize,
158                       int centroids);
159   void RunSpeedTest(av1_calc_indices_dim2_func test_impl, BLOCK_SIZE bsize,
160                     int centroids);
CheckResult(int n)161   bool CheckResult(int n) {
162     bool flag = true;
163     for (int idx = 0; idx < n; ++idx) {
164       if (indices1_[idx] != indices2_[idx]) {
165         printf("%d ", idx);
166         printf("%d != %d ", indices1_[idx], indices2_[idx]);
167         flag = false;
168       }
169     }
170     if (flag == false) {
171       return false;
172     }
173     return true;
174   }
175 
176   libaom_test::ACMRandom rnd_;
177   int data_[4096 * 2];
178   int centroids_[8 * 2];
179   uint8_t indices1_[4096];
180   uint8_t indices2_[4096];
181 };
182 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1KmeansTest2);
183 
~AV1KmeansTest2()184 AV1KmeansTest2::~AV1KmeansTest2() { ; }
185 
SetUp()186 void AV1KmeansTest2::SetUp() {
187   rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
188   for (int i = 0; i < 4096 * 2; ++i) {
189     data_[i] = (int)rnd_.Rand8();
190   }
191   for (int i = 0; i < 8 * 2; i++) {
192     centroids_[i] = (int)rnd_.Rand8();
193   }
194 }
195 
TearDown()196 void AV1KmeansTest2::TearDown() {}
197 
RunCheckOutput(av1_calc_indices_dim2_func test_impl,BLOCK_SIZE bsize,int k)198 void AV1KmeansTest2::RunCheckOutput(av1_calc_indices_dim2_func test_impl,
199                                     BLOCK_SIZE bsize, int k) {
200   const int w = block_size_wide[bsize];
201   const int h = block_size_high[bsize];
202   const int n = w * h;
203   av1_calc_indices_dim2_c(data_, centroids_, indices1_, n, k);
204   test_impl(data_, centroids_, indices2_, n, k);
205 
206   ASSERT_EQ(CheckResult(n), true)
207       << " block " << bsize << " index " << n << " Centroids " << k;
208 }
209 
RunSpeedTest(av1_calc_indices_dim2_func test_impl,BLOCK_SIZE bsize,int k)210 void AV1KmeansTest2::RunSpeedTest(av1_calc_indices_dim2_func test_impl,
211                                   BLOCK_SIZE bsize, int k) {
212   const int w = block_size_wide[bsize];
213   const int h = block_size_high[bsize];
214   const int n = w * h;
215   const int num_loops = 1000000000 / n;
216 
217   av1_calc_indices_dim2_func funcs[2] = { av1_calc_indices_dim2_c, test_impl };
218   double elapsed_time[2] = { 0 };
219   for (int i = 0; i < 2; ++i) {
220     aom_usec_timer timer;
221     aom_usec_timer_start(&timer);
222     av1_calc_indices_dim2_func func = funcs[i];
223     for (int j = 0; j < num_loops; ++j) {
224       func(data_, centroids_, indices1_, n, k);
225     }
226     aom_usec_timer_mark(&timer);
227     double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
228     elapsed_time[i] = 1000.0 * time / num_loops;
229   }
230   printf("av1_calc_indices_dim2 indices= %d centroids=%d: %7.2f/%7.2fns", n, k,
231          elapsed_time[0], elapsed_time[1]);
232   printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
233 }
234 
TEST_P(AV1KmeansTest2,CheckOutput)235 TEST_P(AV1KmeansTest2, CheckOutput) {
236   // centroids = 2..8
237   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 2);
238   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 3);
239   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 4);
240   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 5);
241   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 6);
242   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 7);
243   RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 8);
244 }
245 
TEST_P(AV1KmeansTest2,DISABLED_Speed)246 TEST_P(AV1KmeansTest2, DISABLED_Speed) {
247   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 2);
248   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 3);
249   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 4);
250   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 5);
251   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 6);
252   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 7);
253   RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 8);
254 }
255 
256 #if HAVE_AVX2 || HAVE_SSE2
257 const BLOCK_SIZE kValidBlockSize[] = { BLOCK_8X8,   BLOCK_8X16,  BLOCK_8X32,
258                                        BLOCK_16X8,  BLOCK_16X16, BLOCK_16X32,
259                                        BLOCK_32X8,  BLOCK_32X16, BLOCK_32X32,
260                                        BLOCK_32X64, BLOCK_64X32, BLOCK_64X64,
261                                        BLOCK_16X64, BLOCK_64X16 };
262 #endif
263 
264 #if HAVE_AVX2
265 INSTANTIATE_TEST_SUITE_P(
266     AVX2, AV1KmeansTest1,
267     ::testing::Combine(::testing::Values(&av1_calc_indices_dim1_avx2),
268                        ::testing::ValuesIn(kValidBlockSize)));
269 INSTANTIATE_TEST_SUITE_P(
270     AVX2, AV1KmeansTest2,
271     ::testing::Combine(::testing::Values(&av1_calc_indices_dim2_avx2),
272                        ::testing::ValuesIn(kValidBlockSize)));
273 #endif
274 
275 #if HAVE_SSE2
276 
277 INSTANTIATE_TEST_SUITE_P(
278     SSE2, AV1KmeansTest1,
279     ::testing::Combine(::testing::Values(&av1_calc_indices_dim1_sse2),
280                        ::testing::ValuesIn(kValidBlockSize)));
281 // TODO(any): Disable av1_calc_indices_dim2 sse2 SIMD and its unit test due to
282 // c/SIMD mismatch. Re-enable it after mismatch is fixed.
283 // INSTANTIATE_TEST_SUITE_P(
284 //    SSE2, AV1KmeansTest2,
285 //    ::testing::Combine(::testing::Values(&av1_calc_indices_dim2_sse2),
286 //                       ::testing::ValuesIn(kValidBlockSize)));
287 #endif
288 
289 }  // namespace AV1Kmeans
290