Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leverage CTAD with [MD]RangePolicy #1141

Merged
merged 2 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions benchmarks/dbscan/ArborX_DBSCANVerification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ bool verifyCorePointsNonnegativeIndex(ExecutionSpace const &exec_space,
int num_incorrect;
Kokkos::parallel_reduce(
"ArborX::DBSCAN::verify_core_points_nonnegative",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int i, int &update) {
bool self_is_core_point = (offset(i + 1) - offset(i) >= core_min_size);
if (self_is_core_point && labels(i) < 0)
Expand All @@ -66,7 +66,7 @@ bool verifyConnectedCorePointsShareIndex(ExecutionSpace const &exec_space,
int num_incorrect;
Kokkos::parallel_reduce(
"ArborX::DBSCAN::verify_connected_core_points",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int i, int &update) {
bool self_is_core_point = (offset(i + 1) - offset(i) >= core_min_size);
if (self_is_core_point)
Expand Down Expand Up @@ -105,7 +105,7 @@ bool verifyBorderAndNoisePoints(ExecutionSpace const &exec_space,
int num_incorrect;
Kokkos::parallel_reduce(
"ArborX::DBSCAN::verify_connected_border_points",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int i, int &update) {
bool self_is_core_point = (offset(i + 1) - offset(i) >= core_min_size);
if (!self_is_core_point)
Expand Down
8 changes: 3 additions & 5 deletions benchmarks/dbscan/dbscan_timpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ void sortAndFilterClusters(ExecutionSpace const &exec_space,
"ArborX::DBSCAN::cluster_sizes", n);
Kokkos::parallel_for(
"ArborX::DBSCAN::compute_cluster_sizes",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
KOKKOS_LAMBDA(int const i) {
Kokkos::RangePolicy(exec_space, 0, n), KOKKOS_LAMBDA(int const i) {
// Ignore noise points
if (labels(i) < 0)
return;
Expand All @@ -100,7 +99,7 @@ void sortAndFilterClusters(ExecutionSpace const &exec_space,
KokkosExt::reallocWithoutInitializing(exec_space, cluster_offset, n + 1);
Kokkos::parallel_scan(
"ArborX::DBSCAN::compute_cluster_offset_with_filter",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int const i, int &update, bool final_pass) {
bool is_cluster_too_small = (cluster_sizes(i) < cluster_min_size);
if (!is_cluster_too_small)
Expand Down Expand Up @@ -128,8 +127,7 @@ void sortAndFilterClusters(ExecutionSpace const &exec_space,
KokkosExt::lastElement(exec_space, cluster_offset));
Kokkos::parallel_for(
"ArborX::DBSCAN::compute_cluster_indices",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
KOKKOS_LAMBDA(int const i) {
Kokkos::RangePolicy(exec_space, 0, n), KOKKOS_LAMBDA(int const i) {
// Ignore noise points
if (labels(i) < 0)
return;
Expand Down
3 changes: 1 addition & 2 deletions benchmarks/develop/develop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ void BM_benchmark(benchmark::State &state)
{
// This code gets timed
Kokkos::parallel_for(
"Benchmark::iota",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
"Benchmark::iota", Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int i) { view(i) = i; });
exec_space.fence();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ int main(int argc, char *argv[])
Kokkos::subview(points, Kokkos::make_pair(0, num_primitives)));
Kokkos::parallel_for(
"Benchmark::construct_predicates",
Kokkos::RangePolicy<ExecutionSpace>(
ExecutionSpace{}, p * num_predicates, (p + 1) * num_predicates),
Kokkos::RangePolicy(ExecutionSpace{}, p * num_predicates,
(p + 1) * num_predicates),
KOKKOS_LAMBDA(int i) {
predicates(i) = ArborX::attach(
ArborX::intersects(Sphere{points(i - p * num_predicates), r}), i);
Expand Down
12 changes: 4 additions & 8 deletions benchmarks/triangulated_surface_distance/generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ void convertTriangles2VertexForm(
{
int const num_triangles = triangles.size();
Kokkos::parallel_for(
"Benchmark::to_vertex_form",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, num_triangles),
"Benchmark::to_vertex_form", Kokkos::RangePolicy(space, 0, num_triangles),
KOKKOS_LAMBDA(int i) {
auto const &e0 = edges(triangles(i)[0]);
auto const &e1 = edges(triangles(i)[1]);
Expand Down Expand Up @@ -160,8 +159,7 @@ void subdivide(ExecutionSpace const &space,
"Benchmark::edges"),
2 * num_edges + 3 * num_triangles);
Kokkos::parallel_for(
"Benchmark::split_edges",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, num_edges),
"Benchmark::split_edges", Kokkos::RangePolicy(space, 0, num_edges),
KOKKOS_LAMBDA(int i) {
int v = edges(i)[0];
int w = edges(i)[1];
Expand All @@ -180,8 +178,7 @@ void subdivide(ExecutionSpace const &space,
4 * num_triangles);
Kokkos::parallel_for(
"Benchmark::split_triangles",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, num_triangles),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(space, 0, num_triangles), KOKKOS_LAMBDA(int i) {
int e[3] = {triangles(i)[0], triangles(i)[1], triangles(i)[2]};

int new_edges_offset = 2 * num_edges + 3 * i;
Expand Down Expand Up @@ -219,8 +216,7 @@ void projectVerticesToSphere(
{
Kokkos::parallel_for(
"Benchmark::project_to_surface",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, points.size()),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(space, 0, points.size()), KOKKOS_LAMBDA(int i) {
auto &v = points(i);
auto norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= radius / norm;
Expand Down
12 changes: 4 additions & 8 deletions benchmarks/union_find/union_find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ buildEdges(AllowLoops, ExecutionSpace const &exec_space, int num_edges)

Kokkos::Random_XorShift1024_Pool<ExecutionSpace> rand_pool(1984);
Kokkos::parallel_for(
"Benchmark::init_edges",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, num_edges),
"Benchmark::init_edges", Kokkos::RangePolicy(exec_space, 0, num_edges),
KOKKOS_LAMBDA(unsigned i) {
auto rand_gen = rand_pool.get_state();
do
Expand All @@ -77,8 +76,7 @@ buildEdges(DisallowLoops, ExecutionSpace const &exec_space, int num_edges)
num_edges);
Kokkos::parallel_for(
"Benchmark::init_random_values",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, num_edges),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(exec_space, 0, num_edges), KOKKOS_LAMBDA(int i) {
auto rand_gen = rand_pool.get_state();
random_values(i) = rand_gen.rand();
rand_pool.free_state(rand_gen);
Expand All @@ -91,8 +89,7 @@ buildEdges(DisallowLoops, ExecutionSpace const &exec_space, int num_edges)
"Benchmark::edges"),
num_edges);
Kokkos::parallel_for(
"Benchmark::init_edges",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, num_edges),
"Benchmark::init_edges", Kokkos::RangePolicy(exec_space, 0, num_edges),
KOKKOS_LAMBDA(unsigned i) {
auto rand_gen = rand_pool.get_state();
edges(permute(i)) = {rand_gen.urand() % (i + 1), i + 1};
Expand Down Expand Up @@ -137,8 +134,7 @@ void BM_union_find(benchmark::State &state)

Kokkos::parallel_for(
"Benchmark::union-find",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, edges.size()),
KOKKOS_LAMBDA(int e) {
Kokkos::RangePolicy(exec_space, 0, edges.size()), KOKKOS_LAMBDA(int e) {
int i = edges(e).source;
int j = edges(e).target;

Expand Down
3 changes: 1 addition & 2 deletions benchmarks/utils/ArborXBenchmark_PointClouds.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,7 @@ void generatePointCloud(ExecutionSpace const &exec,
unsigned int const n = random_points.extent(0);
Kokkos::parallel_for(
"ArborXBenchmark::generatePointCloud::generate",
Kokkos::RangePolicy<ExecutionSpace>(exec, 0, n / batch_size),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(exec, 0, n / batch_size), KOKKOS_LAMBDA(int i) {
auto generator = random_pool.get_state();

auto begin = i * batch_size;
Expand Down
2 changes: 1 addition & 1 deletion examples/access_traits/example_cuda_access_traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ int main(int argc, char *argv[])
ArborX::query(bvh, cuda, Spheres{d_a, d_a, d_a, d_a, N}, indices, offset);

Kokkos::parallel_for(
"Example::print_indices", Kokkos::RangePolicy<Kokkos::Cuda>(cuda, 0, N),
"Example::print_indices", Kokkos::RangePolicy(cuda, 0, N),
KOKKOS_LAMBDA(int i) {
for (int j = offset(i); j < offset(i + 1); ++j)
{
Expand Down
14 changes: 5 additions & 9 deletions examples/molecular_dynamics/example_molecular_dynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ int main(int argc, char *argv[])
n);
Kokkos::parallel_for(
"Example::make_particles",
Kokkos::MDRangePolicy<Kokkos::Rank<3>, ExecutionSpace>(
execution_space, {0, 0, 0}, {nx, ny, nz}),
Kokkos::MDRangePolicy(execution_space, {0, 0, 0}, {nx, ny, nz}),
KOKKOS_LAMBDA(int i, int j, int k) {
int const id = i * ny * nz + j * nz + k;
// face-centered cubic arrangement of particles
Expand All @@ -104,8 +103,7 @@ int main(int argc, char *argv[])

Kokkos::parallel_for(
"Example::assign_velocities",
Kokkos::RangePolicy<ExecutionSpace>(execution_space, 0, n),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(execution_space, 0, n), KOKKOS_LAMBDA(int i) {
RandomPool::generator_type generator = random_pool.get_state();
for (int d = 0; d < 3; ++d)
{
Expand All @@ -130,8 +128,7 @@ int main(int argc, char *argv[])
Kokkos::View<float *[3], MemorySpace> forces(
Kokkos::view_alloc(execution_space, "Example::forces"), n);
Kokkos::parallel_for(
"Example::compute_forces",
Kokkos::RangePolicy<ExecutionSpace>(execution_space, 0, n),
"Example::compute_forces", Kokkos::RangePolicy(execution_space, 0, n),
KOKKOS_LAMBDA(int i) {
auto const x_i = particles(i)[0];
auto const y_i = particles(i)[1];
Expand Down Expand Up @@ -170,7 +167,7 @@ int main(int argc, char *argv[])
float potential_energy;
Kokkos::parallel_reduce(
"Example::compute_potential_energy",
Kokkos::RangePolicy<ExecutionSpace>(execution_space, 0, n),
Kokkos::RangePolicy(execution_space, 0, n),
KOKKOS_LAMBDA(int i, float &local_energy) {
auto const x_i = particles(i)[0];
auto const y_i = particles(i)[1];
Expand Down Expand Up @@ -198,8 +195,7 @@ int main(int argc, char *argv[])

Kokkos::parallel_for(
"Example::update_particles_position_and_velocity",
Kokkos::RangePolicy<ExecutionSpace>(execution_space, 0, n),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(execution_space, 0, n), KOKKOS_LAMBDA(int i) {
auto const mass_i = 1.f;
auto const dt_m = dt / mass_i;
for (int d = 0; d < 3; ++d)
Expand Down
5 changes: 2 additions & 3 deletions examples/moving_least_squares/moving_least_squares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ int main(int argc, char *argv[])
Kokkos::View<Point *, MemorySpace> tgt_points("Example::tgt_points",
num_targets);
Kokkos::parallel_for(
"Example::make_points", Kokkos::RangePolicy<ExecutionSpace>(space, 0, 1),
"Example::make_points", Kokkos::RangePolicy(space, 0, 1),
KOKKOS_LAMBDA(int const) {
src_points(0) = {0., 0.};
src_points(1) = {1., 0.};
Expand All @@ -78,8 +78,7 @@ int main(int argc, char *argv[])
Kokkos::View<double *, MemorySpace> ref_values("Example::ref_values",
num_targets);
Kokkos::parallel_for(
"Example::make_values",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, num_sources),
"Example::make_values", Kokkos::RangePolicy(space, 0, num_sources),
KOKKOS_LAMBDA(int const i) {
src_values(i) = functionToApproximate(src_points(i));
if (i < num_targets)
Expand Down
14 changes: 5 additions & 9 deletions examples/raytracing/example_raytracing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,7 @@ int main(int argc, char *argv[])
num_boxes);
Kokkos::parallel_for(
"Example::initialize_boxes",
Kokkos::MDRangePolicy<Kokkos::Rank<3>, ExecutionSpace>(
exec_space, {0, 0, 0}, {nx, ny, nz}),
Kokkos::MDRangePolicy(exec_space, {0, 0, 0}, {nx, ny, nz}),
KOKKOS_LAMBDA(int i, int j, int k) {
int const box_id = i + nx * j + nx * ny * k;
boxes(box_id) = {{i * dx, j * dy, k * dz},
Expand All @@ -248,8 +247,7 @@ int main(int argc, char *argv[])

Kokkos::parallel_for(
"Example::initialize_rays",
Kokkos::MDRangePolicy<Kokkos::Rank<2>, ExecutionSpace>(
exec_space, {0, 0}, {num_boxes, rays_per_box}),
Kokkos::MDRangePolicy(exec_space, {0, 0}, {num_boxes, rays_per_box}),
KOKKOS_LAMBDA(size_t const i, size_t const j) {
// The origins of rays are uniformly distributed in the boxes. The
// direction vectors are uniformly sampling of a full sphere.
Expand Down Expand Up @@ -326,7 +324,7 @@ int main(int argc, char *argv[])
values.size());
Kokkos::parallel_for(
"Example::copy sort_array",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, values.size()),
Kokkos::RangePolicy(exec_space, 0, values.size()),
KOKKOS_LAMBDA(int i) { sort_array(i) = values(i); });
Kokkos::Profiling::pushRegion("Example::sorting by key");
// FIXME Users should not need to reach into the Details namespace.
Expand Down Expand Up @@ -355,8 +353,7 @@ int main(int argc, char *argv[])
"Example::energy_intersects", num_boxes);
Kokkos::parallel_for(
"Example::deposit_energy",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0,
rays_per_box * num_boxes),
Kokkos::RangePolicy(exec_space, 0, rays_per_box * num_boxes),
KOKKOS_LAMBDA(int i) {
float ray_energy = (total_energy * dx * dy * dz) / rays_per_box;
for (int j = offsets(i); j < offsets(i + 1); ++j)
Expand All @@ -377,8 +374,7 @@ int main(int argc, char *argv[])
int n_errors;
float rel_tol = 1.e-5;
Kokkos::parallel_reduce(
"Example::compare",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, num_boxes),
"Example::compare", Kokkos::RangePolicy(exec_space, 0, num_boxes),
KOKKOS_LAMBDA(int i, int &error) {
using Kokkos::fabs;
float const abs_error =
Expand Down
3 changes: 2 additions & 1 deletion examples/viz/tree_visualization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ void viz(std::string const &prefix, std::string const &infile, int n_neighbors)
n_queries);
Kokkos::parallel_for(
"Example::inititialize_queries",
Kokkos::RangePolicy<ExecutionSpace>(0, n_queries), KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(ExecutionSpace{}, 0, n_queries),
KOKKOS_LAMBDA(int i) {
queries(i) = ArborX::nearest(points(i), n_neighbors);
});

Expand Down
12 changes: 4 additions & 8 deletions src/ArborX_DBSCAN.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,7 @@ dbscan(ExecutionSpace const &exec_space, Primitives const &primitives,
// automatically core points
Kokkos::parallel_for(
"ArborX::DBSCAN::mark_dense_cells_core_points",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0,
num_points_in_dense_cells),
Kokkos::RangePolicy(exec_space, 0, num_points_in_dense_cells),
KOKKOS_LAMBDA(int i) { num_neigh(permute(i)) = INT_MAX; });
// Count neighbors for points in sparse cells
auto sparse_permute = Kokkos::subview(
Expand Down Expand Up @@ -449,8 +448,7 @@ dbscan(ExecutionSpace const &exec_space, Primitives const &primitives,
Kokkos::View<int *, MemorySpace> cluster_sizes(
Kokkos::view_alloc(exec_space, "ArborX::DBSCAN::cluster_sizes"), n);
Kokkos::parallel_for(
"ArborX::DBSCAN::finalize_labels",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
"ArborX::DBSCAN::finalize_labels", Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int const i) {
// ##### ECL license (see LICENSE.ECL) #####
int next;
Expand All @@ -474,8 +472,7 @@ dbscan(ExecutionSpace const &exec_space, Primitives const &primitives,
// - DBSCANCorePoints cannot be used either as num_neigh is not initialized
// in the special case.
Kokkos::parallel_for(
"ArborX::DBSCAN::mark_noise",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
"ArborX::DBSCAN::mark_noise", Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int const i) {
if (cluster_sizes(labels(i)) == 1)
labels(i) = -1;
Expand All @@ -485,8 +482,7 @@ dbscan(ExecutionSpace const &exec_space, Primitives const &primitives,
{
Details::DBSCANCorePoints<MemorySpace> is_core{num_neigh, core_min_size};
Kokkos::parallel_for(
"ArborX::DBSCAN::mark_noise",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, n),
"ArborX::DBSCAN::mark_noise", Kokkos::RangePolicy(exec_space, 0, n),
KOKKOS_LAMBDA(int const i) {
if (cluster_sizes(labels(i)) == 1 && !is_core(i))
labels(i) = -1;
Expand Down
2 changes: 1 addition & 1 deletion src/details/ArborX_Dendrogram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct Dendrogram
{
Kokkos::parallel_for(
"ArborX::Dendrogram::copy_weights_and_edges",
Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, edges.size()),
Kokkos::RangePolicy(exec_space, 0, edges.size()),
KOKKOS_LAMBDA(int const e) {
weights(e) = edges(e).weight;
unweighted_edges(e) = {edges(e).source, edges(e).target};
Expand Down
5 changes: 2 additions & 3 deletions src/details/ArborX_DetailsBatchedQueries.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ struct BatchedQueries
n_queries);
Kokkos::parallel_for(
"ArborX::BatchedQueries::project_predicates_onto_space_filling_curve",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, n_queries),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(space, 0, n_queries), KOKKOS_LAMBDA(int i) {
linear_ordering_indices(i) = curve(
scene_bounding_box, returnCentroid(getGeometry(predicates(i))));
});
Expand All @@ -89,7 +88,7 @@ struct BatchedQueries
n);
Kokkos::parallel_for(
"ArborX::BatchedQueries::permute_entries",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, n),
Kokkos::RangePolicy(space, 0, n),
KOKKOS_LAMBDA(int i) { w(i) = v(permute(i)); });

return w;
Expand Down
5 changes: 2 additions & 3 deletions src/details/ArborX_DetailsBruteForceImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct BruteForceImpl
Kokkos::parallel_reduce(
"ArborX::BruteForce::BruteForce::"
"initialize_values_and_reduce_bounds",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, values.size()),
Kokkos::RangePolicy(space, 0, values.size()),
KOKKOS_LAMBDA(int i, Bounds &update) {
using Details::expand;
nodes(i) = values(i);
Expand Down Expand Up @@ -158,8 +158,7 @@ struct BruteForceImpl
Kokkos::parallel_for(
"ArborX::BruteForce::query::nearest::"
"check_all_predicates_against_all_indexables",
Kokkos::RangePolicy<ExecutionSpace>(space, 0, n_predicates),
KOKKOS_LAMBDA(int i) {
Kokkos::RangePolicy(space, 0, n_predicates), KOKKOS_LAMBDA(int i) {
auto const &predicate = predicates(i);
auto const k = getK(predicate);
auto const buffer = buffer_provider(i);
Expand Down
Loading
Loading