Skip to content

Commit

Permalink
Try 1
Browse files Browse the repository at this point in the history
  • Loading branch information
mahbhlddnhakkh committed Apr 14, 2024
1 parent 3fa3aa1 commit 7e6e68c
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 0 deletions.
48 changes: 48 additions & 0 deletions tasks/omp/kulagin_a_gauss_filter_vert/func_tests/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2024 Kulagin Aleksandr
#include <gtest/gtest.h>
#include <omp.h>

#include "omp/kulagin_a_gauss_filter_vert/include/ops_omp.hpp"

void test_case(const size_t& w, const size_t& h, const float& sigma, std::vector<uint32_t> (*generator)(const size_t&, const size_t&)) {
// Create data
std::vector<uint32_t> img = generator(w, h);
std::vector<uint32_t> res(w * h);
std::vector<float> kernel = kulagin_a_gauss::generate_kernel(sigma);
std::vector<uint32_t> out(w * h);
kulagin_a_gauss::apply_filter(w, h, img.data(), kernel.data(), res.data());

// Create TaskData
std::shared_ptr<ppc::core::TaskData> taskDataSeq = std::make_shared<ppc::core::TaskData>();
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(img.data()));
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(kernel.data()));
taskDataSeq->inputs_count.emplace_back(w);
taskDataSeq->inputs_count.emplace_back(h);
taskDataSeq->outputs.emplace_back(reinterpret_cast<uint8_t *>(out.data()));
taskDataSeq->outputs_count.emplace_back(w);
taskDataSeq->outputs_count.emplace_back(h);

// Create Task
FilterGaussVerticalTaskOMPKulagin myTask(taskDataSeq);
ASSERT_EQ(myTask.validation(), true);
ASSERT_EQ(myTask.pre_processing(), true);
ASSERT_EQ(myTask.run(), true);
ASSERT_EQ(myTask.post_processing(), true);
for (size_t i = 0; i < w * h; i++) {
for (size_t j = 0; j < 3; j++) {
uint32_t res_ch = kulagin_a_gauss::get_color_channel(res[i], j);
uint32_t out_ch = kulagin_a_gauss::get_color_channel(out[i], j);
ASSERT_EQ(((res_ch >= out_ch) ? (res_ch - out_ch) : (out_ch - res_ch)) <= 1, true);
}
}
}

TEST(kulagin_a_gauss_filter_vert_omp, test1) { test_case(100, 100, 0.0f, kulagin_a_gauss::generator1); }

TEST(kulagin_a_gauss_filter_vert_omp, test2) { test_case(100, 200, 0.0f, kulagin_a_gauss::generator1); }

TEST(kulagin_a_gauss_filter_vert_omp, test3) { test_case(200, 100, 0.0f, kulagin_a_gauss::generator1); }

TEST(kulagin_a_gauss_filter_vert_omp, test4) { test_case(100, 100, 4.0f, kulagin_a_gauss::generator1); }

TEST(kulagin_a_gauss_filter_vert_omp, test5) { test_case(101, 101, 2.0f, kulagin_a_gauss::generator1); }
150 changes: 150 additions & 0 deletions tasks/omp/kulagin_a_gauss_filter_vert/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2024 Kulagin Aleksandr
#pragma once

#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <limits>
#include <string>
#include <vector>

namespace kulagin_a_gauss {
static const uint32_t default_alpha = 0x0;

inline const uint32_t& get_color(const size_t& w, const size_t&, const uint32_t* img, const size_t& px,
const size_t& py) {
return img[px + py * w];
}

inline uint32_t& get_color(const size_t& w, const size_t&, uint32_t* img, const size_t& px, const size_t& py) {
return img[px + py * w];
}

inline uint32_t get_color_channel(const uint32_t& col, const uint32_t& i) noexcept { return (col >> (i * 8)) & (0xff); }

template <bool is_channel_clean = true>
inline void put_color_channel(uint32_t& col, const uint32_t& ch, const uint32_t& i) noexcept {
if (!is_channel_clean) {
col &= ~(0xff << (i * 8)) & ~(~default_alpha << 24);
}
col |= ((ch & 0xff) << (i * 8));
}

template <bool check_border = true>
inline void apply_filter_pixel(const size_t& w, const size_t& h, const uint32_t* img, const float* kernel,
uint32_t* res_img, const size_t& px, const size_t& py) {
float res_pxl[3] = {0.0f, 0.0f, 0.0f};
uint32_t i;
for (size_t l = 0; l < 3; l++) {
for (size_t k = 0; k < 3; k++) {
size_t dx = px + k - 1;
size_t dy = py + l - 1;
if (check_border) {
if (px == 0 && k == 0) {
dx = 0;
} else if (dx == w) {
dx--;
}
if (py == 0 && l == 0) {
dy = 0;
} else if (dy == h) {
dy--;
}
}
const uint32_t& tmp_col = get_color(w, h, img, dx, dy);
for (i = 0; i < 3; i++) {
res_pxl[i] += (static_cast<float>(get_color_channel(tmp_col, i))) * kernel[k + l * 3];
}
}
}
for (i = 0; i < 3; i++) {
put_color_channel(get_color(w, h, res_img, px, py), std::clamp<uint32_t>(res_pxl[i], 0, 255), i);
}
}

template <bool check_border = true>
inline void apply_filter_line(const size_t& w, const size_t& h, const uint32_t* img, const float* kernel,
uint32_t* res_img, const size_t& x) {
size_t y;
apply_filter_pixel<true>(w, h, img, kernel, res_img, x, 0);
for (y = 1; y < h - 1; y++) {
apply_filter_pixel<check_border>(w, h, img, kernel, res_img, x, y);
}
if (h != 1) {
apply_filter_pixel<true>(w, h, img, kernel, res_img, x, h - 1);
}
}

inline void apply_filter(const size_t& w, const size_t& h, const uint32_t* img, const float* kernel,
uint32_t* img_res) {
kulagin_a_gauss::apply_filter_line<true>(w, h, img, kernel, img_res, 0);
for (size_t x = 1; x < w - 1; x++) {
kulagin_a_gauss::apply_filter_line<false>(w, h, img, kernel, img_res, x);
}
if (w != 1) {
kulagin_a_gauss::apply_filter_line<true>(w, h, img, kernel, img_res, w - 1);
}
}

inline std::vector<uint32_t> generator1(const size_t& w, const size_t& h) {
std::vector<uint32_t> img(w * h);
for (size_t i = 0; i < w * h; i++) {
uint32_t col = 0;
for (size_t j = 0; j < 3; j++) {
put_color_channel(col, (i * (j + 1)) % 256, j);
}
img[i] = col;
}
return img;
}

inline std::vector<float> generate_kernel() { return std::vector<float>(3 * 3, 1.0f / 9.0f); }

inline std::vector<float> generate_kernel(const float& sigma) {
if (std::abs(sigma) <= std::numeric_limits<float>::epsilon() || std::isinf(sigma)) {
// if sigma is 0
return generate_kernel();
}
std::vector<float> kernel(3 * 3);
float norm = 0.0f;
for (size_t i = 0; i < 3; i++) {
const size_t x = i % 2 + 1;
for (size_t j = 0; j < 3; j++) {
const size_t y = j % 2 + 1;
kernel[i + 3 * j] = expf(-static_cast<float>(x * x + y * y) / (2.0f * sigma * sigma));
norm += kernel[i + 3 * j];
}
}
for (size_t i = 0; i < 9; i++) {
kernel[i] /= norm;
}
return kernel;
}

inline std::string generate_path_to_img(const std::string& task, const std::string& task_name,
const std::string& filename) {
return (std::filesystem::path() / PATH_TO_PPC_PROJECT / "tasks" / task / task_name / "data" / filename).string();
}

inline bool get_img_from_file(const std::string& path, std::vector<uint32_t>& img, size_t& w, size_t& h) {
std::ifstream f(path, std::ios::binary | std::ios::in);
if (!f) {
return false;
}
uint32_t _w;
uint32_t _h;
f.read(reinterpret_cast<char*>(&_w), sizeof(uint32_t));
f.read(reinterpret_cast<char*>(&_h), sizeof(uint32_t));
w = _w;
h = _h;
img.resize(w * h);
for (size_t i = 0; i < w * h; i++) {
f.read(reinterpret_cast<char*>(&img[i]), sizeof(uint32_t));
}
f.close();
return f.good();
}
} // namespace kulagin_a_gauss
21 changes: 21 additions & 0 deletions tasks/omp/kulagin_a_gauss_filter_vert/include/ops_omp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2024 Kulagin Aleksandr
#pragma once

#include "core/task/include/task.hpp"
#include "omp/kulagin_a_gauss_filter_vert/include/common.hpp"

class FilterGaussVerticalTaskOMPKulagin : public ppc::core::Task {
public:
explicit FilterGaussVerticalTaskOMPKulagin(std::shared_ptr<ppc::core::TaskData> taskData_)
: Task(std::move(taskData_)) {}
bool pre_processing() override;
bool validation() override;
bool run() override;
bool post_processing() override;

private:
uint32_t* img{};
size_t w{}, h{};
float* kernel{};
std::unique_ptr<uint32_t[]> img_res;
};
99 changes: 99 additions & 0 deletions tasks/omp/kulagin_a_gauss_filter_vert/perf_tests/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2024 Kulagin Aleksandr
#include <gtest/gtest.h>

#include "core/perf/include/perf.hpp"
#include "omp/kulagin_a_gauss_filter_vert/include/ops_omp.hpp"

TEST(kulagin_a_gauss_filter_vert_seq, test_pipeline_run) {
// Create data
size_t w = 1500;
size_t h = 1500;
float sigma = 2.0f;
std::vector<uint32_t> img = kulagin_a_gauss::generator1(w, h);
std::vector<float> kernel = kulagin_a_gauss::generate_kernel(sigma);
std::vector<uint32_t> out(w * h);
std::vector<uint32_t> res(w * h);
kulagin_a_gauss::apply_filter(w, h, img.data(), kernel.data(), res.data());

// Create TaskData
std::shared_ptr<ppc::core::TaskData> taskDataSeq = std::make_shared<ppc::core::TaskData>();
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(img.data()));
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(kernel.data()));
taskDataSeq->inputs_count.emplace_back(w);
taskDataSeq->inputs_count.emplace_back(h);
taskDataSeq->outputs.emplace_back(reinterpret_cast<uint8_t *>(out.data()));
taskDataSeq->outputs_count.emplace_back(w);
taskDataSeq->outputs_count.emplace_back(h);

// Create Task
auto myTask = std::make_shared<FilterGaussVerticalTaskOMPKulagin>(taskDataSeq);

// Create Perf attributes
auto perfAttr = std::make_shared<ppc::core::PerfAttr>();
perfAttr->num_running = 10;
const auto t0 = std::chrono::high_resolution_clock::now();
perfAttr->current_timer = [&] {
auto current_time_point = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(current_time_point - t0).count();
return static_cast<double>(duration) * 1e-9;
};

// Create and init perf results
auto perfResults = std::make_shared<ppc::core::PerfResults>();

// Create Perf analyzer
auto perfAnalyzer = std::make_shared<ppc::core::Perf>(myTask);
perfAnalyzer->pipeline_run(perfAttr, perfResults);
ppc::core::Perf::print_perf_statistic(perfResults);

for (size_t i = 0; i < w * h; i++) {
ASSERT_EQ(res[i], out[i]);
}
}

TEST(kulagin_a_gauss_filter_vert_seq, test_task_run) {
// Create data
size_t w = 1500;
size_t h = 1500;
float sigma = 2.0f;
std::vector<uint32_t> img = kulagin_a_gauss::generator1(w, h);
std::vector<float> kernel = kulagin_a_gauss::generate_kernel(sigma);
std::vector<uint32_t> out(w * h);
std::vector<uint32_t> res(w * h);
kulagin_a_gauss::apply_filter(w, h, img.data(), kernel.data(), res.data());

// Create TaskData
std::shared_ptr<ppc::core::TaskData> taskDataSeq = std::make_shared<ppc::core::TaskData>();
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(img.data()));
taskDataSeq->inputs.emplace_back(reinterpret_cast<uint8_t *>(kernel.data()));
taskDataSeq->inputs_count.emplace_back(w);
taskDataSeq->inputs_count.emplace_back(h);
taskDataSeq->outputs.emplace_back(reinterpret_cast<uint8_t *>(out.data()));
taskDataSeq->outputs_count.emplace_back(w);
taskDataSeq->outputs_count.emplace_back(h);

// Create Task
auto myTask = std::make_shared<FilterGaussVerticalTaskOMPKulagin>(taskDataSeq);

// Create Perf attributes
auto perfAttr = std::make_shared<ppc::core::PerfAttr>();
perfAttr->num_running = 10;
const auto t0 = std::chrono::high_resolution_clock::now();
perfAttr->current_timer = [&] {
auto current_time_point = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(current_time_point - t0).count();
return static_cast<double>(duration) * 1e-9;
};

// Create and init perf results
auto perfResults = std::make_shared<ppc::core::PerfResults>();

// Create Perf analyzer
auto perfAnalyzer = std::make_shared<ppc::core::Perf>(myTask);
perfAnalyzer->task_run(perfAttr, perfResults);
ppc::core::Perf::print_perf_statistic(perfResults);

for (size_t i = 0; i < w * h; i++) {
ASSERT_EQ(res[i], out[i]);
}
}
65 changes: 65 additions & 0 deletions tasks/omp/kulagin_a_gauss_filter_vert/src/ops_omp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 Kulagin Aleksandr
#include "omp/kulagin_a_gauss_filter_vert/include/ops_omp.hpp"

#include <cstring>
#include <exception>
#include <omp.h>

bool FilterGaussVerticalTaskOMPKulagin::pre_processing() {
internal_order_test();
try {
// Init value for input and output
img = reinterpret_cast<uint32_t*>(taskData->inputs[0]);
kernel = reinterpret_cast<float*>(taskData->inputs[1]);
w = taskData->inputs_count[0];
h = taskData->inputs_count[1];
img_res = std::make_unique<uint32_t[]>(w * h);
} catch (std::exception& e) {
std::cout << e.what() << '\n';
return false;
} catch (...) {
std::cout << "Something went very terrible!\n";
return false;
}
return true;
}

bool FilterGaussVerticalTaskOMPKulagin::validation() {
internal_order_test();
// Check count elements of output
return taskData->inputs_count.size() == 2 && taskData->inputs.size() == 2 && taskData->outputs.size() == 1 &&
taskData->inputs_count[0] > 0 && taskData->inputs_count[1] > 0 &&
taskData->inputs_count == taskData->outputs_count && taskData->inputs[0] != nullptr &&
taskData->inputs[1] != nullptr;
}

bool FilterGaussVerticalTaskOMPKulagin::run() {
internal_order_test();
try {
#pragma omp for schedule(static)
for (size_t x = 0; x < w; x++) {
kulagin_a_gauss::apply_filter_line<true>(w, h, img, kernel, img_res.get(), x);
}
} catch (std::exception& e) {
std::cout << e.what() << '\n';
return false;
} catch (...) {
std::cout << "Something went very terrible!\n";
return false;
}
return true;
}

bool FilterGaussVerticalTaskOMPKulagin::post_processing() {
internal_order_test();
try {
std::memcpy(reinterpret_cast<uint32_t*>(taskData->outputs[0]), img_res.get(), w * h * sizeof(uint32_t));
} catch (std::exception& e) {
std::cout << e.what() << '\n';
return false;
} catch (...) {
std::cout << "Something went very terrible!\n";
return false;
}
return true;
}

0 comments on commit 7e6e68c

Please sign in to comment.