
6 changed files with 379 additions and 0 deletions
@ -0,0 +1,110 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include <iostream> |
|||
#include <thread> |
|||
#include <cassert> |
|||
#include <pEp/std_utils.hh> |
|||
#include "../src/CountingSemaphore.hh" |
|||
|
|||
using namespace std; |
|||
using namespace pEp; |
|||
|
|||
thread make_two_threads_for_many_threads() |
|||
{ |
|||
thread res([&]() { |
|||
CountingSemaphore semaphore; |
|||
semaphore = 3; |
|||
|
|||
thread thread1([&]() { |
|||
semaphore.p (); |
|||
semaphore.p (); |
|||
semaphore.p (); |
|||
// Now the count is at 0, assuming the other thread has not
|
|||
// started yet; otherwise it should be at 1.
|
|||
|
|||
semaphore.p (); |
|||
//cout << "1: done\n";
|
|||
}); |
|||
|
|||
Utils::sleep_millis(1000); |
|||
|
|||
thread thread2([&]() { |
|||
semaphore.v(); |
|||
}); |
|||
|
|||
thread1.join(); |
|||
thread2.join(); |
|||
|
|||
assert (semaphore.load() == 0); |
|||
}); |
|||
return res; |
|||
} |
|||
|
|||
void many_threads() |
|||
{ |
|||
int i; |
|||
|
|||
#define N 1000 |
|||
thread threads[N]; |
|||
std::cout << "starting " << N |
|||
<< " threads, each starting and joining a thread pair...\n"; |
|||
for (i = 0; i < N; i ++) |
|||
threads [i] = make_two_threads_for_many_threads (); |
|||
std::cout << "joining threads...\n"; |
|||
for (i = 0; i < N; i ++) |
|||
threads [i].join(); |
|||
#undef N |
|||
std::cout << "many_threads done.\n\n"; |
|||
} |
|||
|
|||
void v_times (CountingSemaphore &semaphore, |
|||
int times) |
|||
{ |
|||
std::cout << "V'ing " << times << " times...\n"; |
|||
for (int i = 0; i < times; i ++) |
|||
semaphore.v (); |
|||
std::cout << "... I V'd " << times << " times.\n"; |
|||
} |
|||
|
|||
void p_times (CountingSemaphore &semaphore, |
|||
int times) |
|||
{ |
|||
std::cout << "P'ing " << times << " times...\n"; |
|||
for (int i = 0; i < times; i ++) |
|||
semaphore.p (); |
|||
std::cout << "... I P'd " << times << " times.\n"; |
|||
} |
|||
|
|||
void few_threads() |
|||
{ |
|||
#define HALF_N (1000 * 1000 * 10) |
|||
#define N (HALF_N * 2) |
|||
CountingSemaphore semaphore; |
|||
|
|||
thread thread_p1([&]() { |
|||
p_times (semaphore, HALF_N); |
|||
}); |
|||
thread thread_v([&]() { |
|||
v_times (semaphore, N); |
|||
}); |
|||
thread thread_p2([&]() { |
|||
p_times (semaphore, HALF_N); |
|||
}); |
|||
#undef HALF_N |
|||
#undef N |
|||
thread_v.join(); |
|||
thread_p1.join(); |
|||
thread_p2.join(); |
|||
|
|||
assert (semaphore.load() == 0); |
|||
|
|||
std::cout << "few_thrads done.\n\n"; |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
many_threads (); |
|||
few_threads (); |
|||
return 0; |
|||
} |
@ -0,0 +1,24 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
#include <iostream> |
|||
#include <cassert> |
|||
|
|||
#include <pEp/pEpLog.hh> |
|||
#include <pEp/std_utils.hh> |
|||
|
|||
int main(int argc, char* argv[]) |
|||
{ |
|||
pEp::Adapter::pEpLog::set_enabled(true); |
|||
std::string filename = "test_rw.bin"; |
|||
|
|||
std::vector<char> v_out{}; |
|||
for (int i = 0; i < 1000; i++) { |
|||
v_out.push_back(pEp::Utils::random_char(0, 255)); |
|||
} |
|||
|
|||
pEp::Utils::file_write_bin(filename, v_out); |
|||
|
|||
std::vector<char> v_in = pEp::Utils::file_read_bin(filename); |
|||
|
|||
assert(v_in == v_out); |
|||
} |
@ -0,0 +1,39 @@ |
|||
#include <pEp/std_utils.hh> |
|||
#include <pEp/pEpLog.hh> |
|||
#include <iostream> |
|||
#include <cassert> |
|||
#include <pEp/pitytest11/PityTest.hh> |
|||
|
|||
using namespace pEp; |
|||
|
|||
int main() |
|||
{ |
|||
pEp::Adapter::pEpLog::set_enabled(true); |
|||
|
|||
{ |
|||
// Valid hex string
|
|||
std::string str_in{ "FFABCD00EF123200" }; |
|||
std::vector<unsigned char> bin = Utils::hex2bin<unsigned char>(str_in); |
|||
PITYASSERT(str_in.length() == bin.size() * 2, "Size error"); |
|||
|
|||
std::string str_out = pEp::Utils::bin2hex(bin); |
|||
pEpLog("Hex_IN : '" + Utils::to_lower(str_in) + "'"); |
|||
pEpLog("Hex_OUT : '" + Utils::to_lower(str_out) + "'"); |
|||
|
|||
PITYASSERT(Utils::to_lower(str_in) == Utils::to_lower(str_out), "roundtrip failed"); |
|||
} |
|||
|
|||
{ |
|||
// Uneven string throws
|
|||
std::string str_in{ "FFA" }; |
|||
PITYASSERT_THROWS(Utils::hex2bin<char>(str_in), "Uneven string should throw"); |
|||
} |
|||
|
|||
{ |
|||
// Non-hex chars
|
|||
std::string str_in{ "pEp!" }; |
|||
PITYASSERT_THROWS(Utils::hex2bin<char>(str_in), "Invalid hex chars should throw"); |
|||
} |
|||
|
|||
pEpLog("All tests passsed"); |
|||
} |
@ -0,0 +1,105 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "pc_container.hh" |
|||
#include <cstdio> |
|||
#include <cstdlib> |
|||
#include <iostream> |
|||
#include <thread> |
|||
|
|||
using namespace pEp; |
|||
|
|||
// Producer's data:
|
|||
class P { |
|||
public: |
|||
P(int i) : data{ new char[64] } |
|||
{ |
|||
snprintf(data, 63, "%i", i); |
|||
} |
|||
|
|||
P(const P&) = delete; |
|||
void operator=(const P&) = delete; |
|||
|
|||
~P() |
|||
{ |
|||
std::cerr << "~P(): data=" << (data ? data : "(NULL)") << '\n'; |
|||
delete[] data; |
|||
} |
|||
|
|||
char* data; |
|||
}; |
|||
|
|||
|
|||
// Consumer's data:
|
|||
class C { |
|||
public: |
|||
C(int _i) : i(_i) {} |
|||
int i; |
|||
}; |
|||
|
|||
pc_container<P, C> pc; |
|||
|
|||
void consumer_thread() |
|||
{ |
|||
bool keep_running = true; |
|||
int sum = 0; |
|||
while (keep_running) { |
|||
for (auto& q : pc) { |
|||
switch (q.state()) { |
|||
case PC_State::Created: { |
|||
const int value = atoi(q.pdata->data); |
|||
if (value < 0) { |
|||
std::cerr << "Q\n"; |
|||
keep_running = false; |
|||
} else { |
|||
std::cerr << "C"; |
|||
q.cdata = new C(value); |
|||
sum += q.cdata->i; |
|||
} |
|||
break; |
|||
} |
|||
case PC_State::Deleted: { |
|||
std::cerr << "D"; |
|||
sum -= q.cdata->i; |
|||
delete q.cdata; |
|||
break; |
|||
} |
|||
case PC_State::Changed: { |
|||
std::cerr << "X"; |
|||
sum -= q.cdata->i; |
|||
delete q.cdata; |
|||
q.cdata = new C(atoi(q.pdata->data)); |
|||
sum += q.cdata->i; |
|||
break; |
|||
} |
|||
default: |
|||
throw "Illegal state"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
std::cout << "Consumer sum: " << sum << ".\n"; |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
for (int i = 0; i < 10; ++i) { |
|||
pc.insert(new P(i)); |
|||
} |
|||
|
|||
std::thread t{ &consumer_thread }; |
|||
|
|||
for (int i = 10; i < 100; ++i) { |
|||
pc.insert(new P(i)); |
|||
} |
|||
|
|||
while (!pc.empty()) { |
|||
auto q = pc.begin(); |
|||
delete q->pdata; |
|||
pc.erase(q); |
|||
} |
|||
|
|||
pc.insert(new P(-1)); |
|||
|
|||
t.join(); |
|||
} |
@ -0,0 +1,64 @@ |
|||
#include <pEp/std_utils.hh> |
|||
#include <pEp/pEpLog.hh> |
|||
#include <pEp/pitytest11/PityTest.hh> |
|||
#include <iostream> |
|||
#include <chrono> |
|||
|
|||
using namespace pEp; |
|||
|
|||
|
|||
int test_random_string_fast() |
|||
{ |
|||
pEpLog("Test test_random_string_fast() correct length, min & max"); |
|||
for (int i = 0; i < 1000; i++) { |
|||
uint len = Utils::random_fast(5000); |
|||
std::string res = Utils::random_string_fast(0, 255, len); |
|||
PITYASSERT( |
|||
res.length() == len, |
|||
"random_string_fast: wrong length: " + |
|||
std::to_string(res.length()) + " is not " + std::to_string(len)); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
pEp::Adapter::pEpLog::set_enabled(true); |
|||
|
|||
test_random_string_fast(); |
|||
|
|||
pEpLog("Random functions benchmark"); |
|||
int nr_mb = 10; |
|||
int nr_bytes = 1024 * 1024 * nr_mb; |
|||
pEpLog("generating " + std::to_string(nr_mb) + "MB's of random"); |
|||
|
|||
{ |
|||
pEpLog("Utils::random_char()"); |
|||
auto time_start = std::chrono::steady_clock::now(); |
|||
for (int i = 0; i < nr_bytes; i++) { |
|||
Utils::random_char(0, 255); |
|||
} |
|||
auto time_end = std::chrono::steady_clock::now(); |
|||
double duration_ms = (double)std::chrono::duration_cast<std::chrono::microseconds>( |
|||
time_end - time_start) |
|||
.count() / |
|||
1000; |
|||
pEpLog("Time [ms/mbyte]:" + std::to_string(duration_ms / double(nr_mb))); |
|||
} |
|||
std::cout << "" << std::endl; |
|||
{ |
|||
pEpLog("Utils::Fastrand()"); |
|||
auto time_start = std::chrono::steady_clock::now(); |
|||
for (int i = 0; i < nr_bytes; i++) { |
|||
Utils::random_fast(255); |
|||
} |
|||
auto time_end = std::chrono::steady_clock::now(); |
|||
double duration_ms = (double)std::chrono::duration_cast<std::chrono::microseconds>( |
|||
time_end - time_start) |
|||
.count() / |
|||
1000; |
|||
|
|||
pEpLog("Time [ms/mbyte]:" + std::to_string(duration_ms / double(nr_mb))); |
|||
} |
|||
return 0; |
|||
} |
@ -0,0 +1,37 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include <iostream> |
|||
#include <thread> |
|||
#include <pEp/std_utils.hh> |
|||
#include "../src/Semaphore.hh" |
|||
|
|||
using namespace std; |
|||
using namespace pEp; |
|||
|
|||
int main() |
|||
{ |
|||
Semaphore semaphore; |
|||
|
|||
thread thread1([&]() { |
|||
cout << "1: before stop\n"; |
|||
semaphore.stop(); |
|||
cout << "1: now on stop\n"; |
|||
semaphore.try_wait(); |
|||
cout << "1: and on go again\n"; |
|||
semaphore.try_wait(); |
|||
cout << "1: keep going\n"; |
|||
}); |
|||
|
|||
Utils::sleep_millis(1000); |
|||
|
|||
thread thread2([&]() { |
|||
cout << "2: setting go\n"; |
|||
semaphore.go(); |
|||
}); |
|||
|
|||
thread1.join(); |
|||
thread2.join(); |
|||
|
|||
return 0; |
|||
} |
Loading…
Reference in new issue