mesytec-mnode/external/taskflow-3.8.0/benchmarks/deferred_pipeline/pthread.cpp

179 lines
4.5 KiB
C++
Raw Normal View History

2025-01-04 01:25:05 +01:00
#include "deferred_pipeline.hpp"
#include <taskflow/taskflow.hpp>
#include <taskflow/algorithm/pipeline.hpp>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <cassert>
class Frame {
public:
bool processed = false;
size_t fid;
char ftype;
std::mutex m;
std::condition_variable cv;
std::vector<int> depend_on;
Frame(size_t i, char t) : fid{i}, ftype{t} {}
};
std::vector<std::unique_ptr<Frame>> video;
std::vector<int> vec1;
std::mutex global_m;
void encode_frame(const size_t idx, const size_t num_threads,
const size_t num_frames) {
size_t fid;
size_t iterations = 1+(num_frames-1)/num_threads;
for (size_t i = 0; i < iterations; ++i) {
fid = num_threads*i+idx;
if (fid >= num_frames) {
break;
}
// I frame does not have any depency
if (video[fid]->ftype == 'I') {
std::unique_lock lk(video[fid]->m);
work_I();
video[fid]->processed = true;
video[fid]->cv.notify_all();
continue;
}
else if (video[fid]->ftype == 'P') {
// wait on the dependency
{
int depend_on_id = video[fid]->depend_on[0];
std::unique_lock lk(video[depend_on_id]->m);
video[depend_on_id]->cv.wait(lk, [&]{
return video[depend_on_id]->processed;
});
}
// dependency is resolved
{
std::unique_lock lk(video[fid]->m);
work_P();
video[fid]->processed = true;
video[fid]->cv.notify_all();
}
}
else {
// wait on the first dependency
int depend_on_id = video[fid]->depend_on[0];
{
std::unique_lock lk(video[depend_on_id]->m);
video[depend_on_id]->cv.wait(lk, [&]{
return video[depend_on_id]->processed;
});
}
// wait on the second dependency
if (video[fid]->depend_on.size() > 1) {
depend_on_id = video[fid]->depend_on[1];
}
{
std::unique_lock lk(video[depend_on_id]->m);
video[depend_on_id]->cv.wait(lk, [&]{
return video[depend_on_id]->processed;
});
}
// dependency is resolved
{
std::unique_lock lk(video[fid]->m);
work_B();
video[fid]->processed = true;
video[fid]->cv.notify_all();
}
}
}
}
std::chrono::microseconds measure_time_pthread(
size_t num_threads, std::string type, size_t num_frames) {
std::chrono::microseconds elapsed;
std::vector<std::thread> threads;
for (size_t i = 0; i < num_frames; ++i) {
// x264 frame pattern is viedo_1
// video_1 has 128 frames in total
if (type == "1") {
std::unique_ptr<Frame> p(new Frame(i, video_1[i%128]));
video.emplace_back(std::move(p));
}
// x264 frame pattern is video_2.
// video_2 has 300 frames in total.
else {
std::unique_ptr<Frame> p(new Frame(i, video_2[i%300]));
video.emplace_back(std::move(p));
}
}
// construct the depend_on vector of each frame
for (size_t i = 0; i < num_frames; ++i) {
// I frames do not depend on other frames
if (video[i]->ftype == 'I') {
continue;
}
// P frames depend on its previous I or P frame
// have one dependency
else if (video[i]->ftype == 'P') {
int p_idx = i-1;
while(p_idx >= 0) {
if (video[p_idx]->ftype == 'I' || video[p_idx]->ftype == 'P') {
video[i]->depend_on.push_back(p_idx);
break;
}
--p_idx;
}
}
// B frames depend on its previous I or P frame and its later I or P frame
// have up to two dependencies
else {
int p_idx = i-1, l_idx = i+1;
while(p_idx >= 0) {
if (video[p_idx]->ftype == 'I' || video[p_idx]->ftype == 'P') {
video[i]->depend_on.push_back(p_idx);
break;
}
--p_idx;
}
while(l_idx < static_cast<int>(num_frames)) {
if (video[l_idx]->ftype == 'I' || video[l_idx]->ftype == 'P') {
video[i]->depend_on.push_back(l_idx);
break;
}
++l_idx;
}
}
}
auto beg = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < num_threads; ++i) {
threads.emplace_back(
std::thread(encode_frame, i, num_threads, num_frames));
}
// join all threads
for (size_t i = 0; i < num_threads; ++i) {
threads[i].join();
}
auto end = std::chrono::high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - beg);
return elapsed;
}