|
|
@@ -6,75 +6,110 @@ |
|
|
|
* |
|
|
|
* Unless required by applicable law or agreed to in writing, |
|
|
|
* software distributed under the License is distributed on an |
|
|
|
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
|
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
|
|
* implied. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "megdnn/basic_types.h" |
|
|
|
#include "test/common/utils.h" |
|
|
|
#include "test/common/timer.h" |
|
|
|
#include "test/common/utils.h" |
|
|
|
|
|
|
|
#include <random> |
|
|
|
#include <gtest/gtest.h> |
|
|
|
#include <random> |
|
|
|
|
|
|
|
using namespace megdnn; |
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
bool eq_shape0(const TensorShape &a, const TensorShape &b) { |
|
|
|
bool eq_shape0(const TensorShape& a, const TensorShape& b) { |
|
|
|
if (a.ndim != b.ndim) |
|
|
|
return false; |
|
|
|
return std::equal(a.shape, a.shape + a.ndim, b.shape); |
|
|
|
} |
|
|
|
|
|
|
|
bool eq_shape1(const TensorShape &a, const TensorShape &b) { |
|
|
|
bool eq_shape1(const TensorShape& a, const TensorShape& b) { |
|
|
|
if (a.ndim == b.ndim) { |
|
|
|
size_t eq = 0; |
|
|
|
switch (a.ndim) { |
|
|
|
case 6: eq += a.shape[5] == b.shape[5]; MEGDNN_FALLTHRU |
|
|
|
case 5: eq += a.shape[4] == b.shape[4]; MEGDNN_FALLTHRU |
|
|
|
case 4: eq += a.shape[3] == b.shape[3]; MEGDNN_FALLTHRU |
|
|
|
case 3: eq += a.shape[2] == b.shape[2]; MEGDNN_FALLTHRU |
|
|
|
case 2: eq += a.shape[1] == b.shape[1]; MEGDNN_FALLTHRU |
|
|
|
case 1: eq += a.shape[0] == b.shape[0]; |
|
|
|
case 7: |
|
|
|
eq += a.shape[6] == b.shape[6]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 6: |
|
|
|
eq += a.shape[5] == b.shape[5]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 5: |
|
|
|
eq += a.shape[4] == b.shape[4]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 4: |
|
|
|
eq += a.shape[3] == b.shape[3]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 3: |
|
|
|
eq += a.shape[2] == b.shape[2]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 2: |
|
|
|
eq += a.shape[1] == b.shape[1]; |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 1: |
|
|
|
eq += a.shape[0] == b.shape[0]; |
|
|
|
} |
|
|
|
return eq == a.ndim; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
bool eq_layout0(const TensorLayout &a, const TensorLayout &b) { |
|
|
|
bool eq_layout0(const TensorLayout& a, const TensorLayout& b) { |
|
|
|
if (!eq_shape0(a, b)) |
|
|
|
return false; |
|
|
|
|
|
|
|
return std::equal(a.stride, a.stride + a.ndim, b.stride); |
|
|
|
} |
|
|
|
|
|
|
|
bool eq_layout1(const TensorLayout &a, const TensorLayout &b) { |
|
|
|
auto ax = [](size_t shape0, size_t shape1, |
|
|
|
ptrdiff_t stride0, ptrdiff_t stride1) { |
|
|
|
bool eq_layout1(const TensorLayout& a, const TensorLayout& b) { |
|
|
|
auto ax = [](size_t shape0, size_t shape1, ptrdiff_t stride0, |
|
|
|
ptrdiff_t stride1) { |
|
|
|
return (shape0 == shape1) & ((shape0 == 1) | (stride0 == stride1)); |
|
|
|
}; |
|
|
|
if (a.ndim == b.ndim) { |
|
|
|
size_t eq = 0; |
|
|
|
switch (a.ndim) { |
|
|
|
case 6: eq += ax(a.shape[5], b.shape[5], a.stride[5], b.stride[5]); MEGDNN_FALLTHRU |
|
|
|
case 5: eq += ax(a.shape[4], b.shape[4], a.stride[4], b.stride[4]); MEGDNN_FALLTHRU |
|
|
|
case 4: eq += ax(a.shape[3], b.shape[3], a.stride[3], b.stride[3]); MEGDNN_FALLTHRU |
|
|
|
case 3: eq += ax(a.shape[2], b.shape[2], a.stride[2], b.stride[2]); MEGDNN_FALLTHRU |
|
|
|
case 2: eq += ax(a.shape[1], b.shape[1], a.stride[1], b.stride[1]); MEGDNN_FALLTHRU |
|
|
|
case 1: eq += ax(a.shape[0], b.shape[0], a.stride[0], b.stride[0]); |
|
|
|
case 7: |
|
|
|
eq += ax(a.shape[6], b.shape[6], a.stride[6], b.stride[6]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 6: |
|
|
|
eq += ax(a.shape[5], b.shape[5], a.stride[5], b.stride[5]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 5: |
|
|
|
eq += ax(a.shape[4], b.shape[4], a.stride[4], b.stride[4]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 4: |
|
|
|
eq += ax(a.shape[3], b.shape[3], a.stride[3], b.stride[3]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 3: |
|
|
|
eq += ax(a.shape[2], b.shape[2], a.stride[2], b.stride[2]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 2: |
|
|
|
eq += ax(a.shape[1], b.shape[1], a.stride[1], b.stride[1]); |
|
|
|
MEGDNN_FALLTHRU |
|
|
|
case 1: |
|
|
|
eq += ax(a.shape[0], b.shape[0], a.stride[0], b.stride[0]); |
|
|
|
} |
|
|
|
return eq == a.ndim; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
} // anonymous namespace |
|
|
|
} // anonymous namespace |
|
|
|
// config NR_TEST at small memory device, eg, EV300 etc |
|
|
|
static constexpr size_t NR_TEST = 10000; |
|
|
|
TEST(BENCHMARK_BASIC_TYPES, EQ_SHAPE) { |
|
|
|
std::mt19937_64 rng; |
|
|
|
static TensorShape s0, s1[NR_TEST]; |
|
|
|
auto init = [&rng](TensorShape& ts) { |
|
|
|
for (size_t i = 0; i < ts.ndim; ++i) |
|
|
|
ts.shape[i] = rng(); |
|
|
|
}; |
|
|
|
s0.ndim = rng() % TensorShape::MAX_NDIM + 1; |
|
|
|
init(s0); |
|
|
|
auto gen = [&](int type) { |
|
|
|
if (type == 0) { |
|
|
|
return s0; |
|
|
@@ -84,39 +119,45 @@ TEST(BENCHMARK_BASIC_TYPES, EQ_SHAPE) { |
|
|
|
ret.ndim = s0.ndim; |
|
|
|
else |
|
|
|
ret.ndim = rng() % TensorShape::MAX_NDIM + 1; |
|
|
|
for (size_t i = 0; i < ret.ndim; ++ i) |
|
|
|
ret.shape[i] = rng(); |
|
|
|
init(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
}; |
|
|
|
s0 = gen(false); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) { |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) { |
|
|
|
s1[i] = gen(rng() % 3); |
|
|
|
} |
|
|
|
|
|
|
|
int nr_diff = 0; |
|
|
|
test::Timer timer; |
|
|
|
timer.start(); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) |
|
|
|
nr_diff += eq_shape0(s1[i], s0); |
|
|
|
timer.stop(); |
|
|
|
auto time0 = timer.get_time_in_us(); |
|
|
|
|
|
|
|
timer.reset(); |
|
|
|
timer.start(); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) |
|
|
|
nr_diff -= eq_shape1(s1[i], s0); |
|
|
|
timer.stop(); |
|
|
|
auto time1 = timer.get_time_in_us(); |
|
|
|
|
|
|
|
printf("time per eq_shape: %.3fus vs %.3fus; diff=%d\n", |
|
|
|
time0 / double(NR_TEST), time1 / double(NR_TEST), |
|
|
|
nr_diff); |
|
|
|
time0 / double(NR_TEST), time1 / double(NR_TEST), nr_diff); |
|
|
|
} |
|
|
|
|
|
|
|
TEST(BENCHMARK_BASIC_TYPES, EQ_LAYOUT) { |
|
|
|
std::mt19937_64 rng; |
|
|
|
static TensorLayout s0, s1[NR_TEST]; |
|
|
|
auto init = [&rng](TensorLayout& tl) { |
|
|
|
for (size_t i = 0; i < tl.ndim; ++i) { |
|
|
|
tl.shape[i] = rng(); |
|
|
|
tl.stride[i] = rng(); |
|
|
|
} |
|
|
|
}; |
|
|
|
s0.ndim = rng() % TensorShape::MAX_NDIM + 1; |
|
|
|
init(s0); |
|
|
|
auto gen = [&](int type) { |
|
|
|
if (type == 0) { |
|
|
|
return s0; |
|
|
@@ -126,35 +167,31 @@ TEST(BENCHMARK_BASIC_TYPES, EQ_LAYOUT) { |
|
|
|
ret.ndim = s0.ndim; |
|
|
|
else |
|
|
|
ret.ndim = rng() % TensorShape::MAX_NDIM + 1; |
|
|
|
for (size_t i = 0; i < ret.ndim; ++ i) { |
|
|
|
ret.shape[i] = rng(); |
|
|
|
ret.stride[i] = rng(); |
|
|
|
} |
|
|
|
init(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
}; |
|
|
|
s0 = gen(false); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) { |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) { |
|
|
|
s1[i] = gen(rng() % 3); |
|
|
|
} |
|
|
|
|
|
|
|
int nr_diff = 0; |
|
|
|
test::Timer timer; |
|
|
|
timer.start(); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) |
|
|
|
nr_diff += eq_layout0(s1[i], s0); |
|
|
|
timer.stop(); |
|
|
|
auto time0 = timer.get_time_in_us(); |
|
|
|
|
|
|
|
timer.reset(); |
|
|
|
timer.start(); |
|
|
|
for (size_t i = 0; i < NR_TEST; ++ i) |
|
|
|
for (size_t i = 0; i < NR_TEST; ++i) |
|
|
|
nr_diff -= eq_layout1(s1[i], s0); |
|
|
|
timer.stop(); |
|
|
|
auto time1 = timer.get_time_in_us(); |
|
|
|
|
|
|
|
printf("time per eq_layout: %.3fus vs %.3fus; diff=%d\n", |
|
|
|
time0 / double(NR_TEST), time1 / double(NR_TEST), |
|
|
|
nr_diff); |
|
|
|
time0 / double(NR_TEST), time1 / double(NR_TEST), nr_diff); |
|
|
|
} |
|
|
|
// vim: syntax=cpp.doxygen |