I wrote a test for my application in modern C++ based on C++ lib of swipl. The test program runs very well on itself in pure C++:
int main() {
srand(time(0));
Person person;
auto start = steady_clock::now();
string persons = person.concGenPersons(1, 1000000);
auto end = steady_clock::now();
cout << "time used in milliseconds:"
<< duration_cast<milliseconds>(end - start).count() << endl;
return 0;
}
--------------
Arthurs-MacBook-Pro:swipl-dict-db laowang$ test/gendata
time used in milliseconds:565
Arthurs-MacBook-Pro:swipl-dict-db laowang$ test/gendata
time used in milliseconds:520
Arthurs-MacBook-Pro:swipl-dict-db laowang$ test/gendata
time used in milliseconds:519
Arthurs-MacBook-Pro:swipl-dict-db laowang$ test/gendata
time used in milliseconds:511
Arthurs-MacBook-Pro:swipl-dict-db laowang$ test/gendata
time used in milliseconds:524
But when I run it in swipl, it often crashed even using much less data.
PREDICATE(conc_gen_persons, 3) {
srand(time(0));
int fromId((int)A1);
int toId((int)A2);
try {
Person p;
string dictsStr = p.concGenPersons(fromId, toId);
cout << "length:" << dictsStr.size() << endl;
A3 = (PlCompound)(dictsStr.c_str());
} catch (const exception &e) {
throw Utils::genPlException("conc_gen_persons_exception", string(e.what()));
} catch (...) {
throw Utils::genPlException("conc_gen_persons_exception",
string("unknown reason"));
}
return TRUE;
}
-------------------------
?- time(ddtest:conc_gen_persons(1,100000,D)),length(D,L).
SWI-Prolog [thread -1 () at Tue Aug 20 15:10:11 2019]: received fatal signal 11 (segv)
C-stack trace labeled "crash":
[0] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(save_backtrace+0x62) [0x102112042]
[1] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(print_c_backtrace+0x15) [0x102112915]
[2] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(sigCrashHandler+0xf4) [0x102112824]
[3] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(dispatch_signal+0x6d) [0x10207336d]
[4] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(pl_signal_handler+0x15) [0x102076155]
[5] /usr/lib/system/libsystem_platform.dylib(_sigtramp+0x1d) [0x7fff63408b5d]
[7] /usr/local/opt/llvm/lib/libc++.1.dylib(_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2ERKS5_+0x87) [0x1026c0713]
[8] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZN6Person13getARandomStrERKNSt3__16vectorINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEENS5_IS7_EEEE+0x67) [0x102405cf7]
[9] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZN6Person9getALNameEv+0x24) [0x102405a64]
[10] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZN6Person10genAPersonEm+0x1df) [0x10240539f]
[11] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZN6Person10genPersonsEii+0x5b) [0x102404c6b]
[12] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZN6Person16genPersonsThreadEii+0x30) [0x102404f10]
[13] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__18__invokeIM6PersonFviiEPS1_JiiEvEEDTcldsdeclsr3std3__1E7forwardIT0_Efp0_Efp_spclsr3std3__1E7forwardIT1_Efp1_EEEOT_OS5_DpOS6_+0x9d) [0x10240794d]
[14] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__112__async_funcIM6PersonFviiEJPS1_iiEE9__executeIJLm1ELm2ELm3EEEEvNS_15__tuple_indicesIJXspT_EEEE+0x74) [0x1024078a4]
[15] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__112__async_funcIM6PersonFviiEJPS1_iiEEclEv+0x15) [0x102407825]
[16] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__119__async_assoc_stateIvNS_12__async_funcIM6PersonFviiEJPS2_iiEEEE9__executeEv+0x25) [0x1024076b5]
[17] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__18__invokeIMNS_19__async_assoc_stateIvNS_12__async_funcIM6PersonFviiEJPS3_iiEEEEEFvvEPS8_JEvEEDTcldsdeclsr3std3__1E7forwardIT0_Efp0_Efp_spclsr3std3__1E7forwardIT1_Efp1_EEEOT_OSC_DpOSD_+0x71) [0x102408851]
[18] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__116__thread_executeINS_10unique_ptrINS_15__thread_structENS_14default_deleteIS2_EEEEMNS_19__async_assoc_stateIvNS_12__async_funcIM6PersonFviiEJPS8_iiEEEEEFvvEJPSD_EJLm2EEEEvRNS_5tupleIJT_T0_DpT1_EEENS_15__tuple_indicesIJXspT2_EEEE+0x3e) [0x10240875e]
[19] /Users/laowang/workspace/swipl-dict-db/lib/dbdict.dylib(_ZNSt3__114__thread_proxyINS_5tupleIJNS_10unique_ptrINS_15__thread_structENS_14default_deleteIS3_EEEEMNS_19__async_assoc_stateIvNS_12__async_funcIM6PersonFviiEJPS9_iiEEEEEFvvEPSE_EEEEEPvSJ_+0x76) [0x102407f56]
[20] /usr/lib/system/libsystem_pthread.dylib(_pthread_body+0x7e) [0x7fff634112eb]
[21] /usr/lib/system/libsystem_pthread.dylib(_pthread_start+0x42) [0x7fff63414249]
[22] /usr/lib/system/libsystem_pthread.dylib(thread_start+0xd) [0x7fff6341040d]
Running on_halt hooks with status 139
Killing 50544 with default signal handlers
Segmentation fault: 11
--------------------------------------
Somtimes it sucesses as follows:
?- time(ddtest:conc_gen_persons(1,100000,D)),length(D,L).
length:8814874
% 2 inferences, 0.772 CPU in 0.830 seconds (93% CPU, 3 Lips)
D = [person{dob:'1952-5-27', first_name:'Tracy', gender:male, id:25001, last_name:'Sellards'}, person{dob:'1984-5-7', first_name:'Sarai', gender:female, id:25002, last_name:'Royer'}, person{dob:'1975-11-3', first_name:'Shelby', gender:male, id:25003, last_name:'Wainer'}, person{dob:'1988-1-13', first_name:'Juan', gender:male, id:25004, last_name:'Drinkwater'}, person{dob:'1985-10-7', first_name:'Nickie', gender:female, id:25005, last_name:'Plesnarski'}, person{dob:'1980-8-22', first_name:'Spring', gender:female, id:25006, last_name:'Delee'}, person{dob:'1958-3-29', first_name:'Harry', gender:male, id:25007, last_name:'Falkner'}, person{dob:'1982-12-18', first_name:'Kaycee', gender:female, id:25008, last_name:'Darrell'}, ...{... : ..., ... : ..., ... : ..., ... : ..., ... : ...}|...],
L = 100000.
----------------------------------
ps. I've set a big stack_limit value:
?- current_prolog_flag(stack_limit, V).
V = 8589934592.
BTW, ddtest:conc_gen_persons/3 is a member function in concurrency.
The whole source file is attached below for reference:
#define PROLOG_MODULE "ddtest"
// #include "../cxxsrc/Utils.hpp"
// #include <SWI-cpp.h>
#include <chrono>
#include <condition_variable>
#include <cstdlib>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <future>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
using namespace std;
using namespace std::chrono;
class Person {
private:
vector<string> lnames_;
vector<string> mfnames_;
vector<string> ffnames_;
unsigned int concurrency_;
mutex readyMutex_;
condition_variable readyCV_;
string resultStr_;
int readyCount_;
bool getLinesToVector(const char *file, vector<string> &strings) {
ifstream in(file);
if (!in) {
cerr << "Error opening file:" << file << endl;
return false;
}
string str;
while (getline(in, str)) {
if (str.size() > 0)
strings.push_back(str);
}
in.close();
return true;
}
bool initData() {
concurrency_ = thread::hardware_concurrency();
if (concurrency_ == 0)
concurrency_ = 2;
return getLinesToVector("test/last-names.txt", lnames_) &&
getLinesToVector("test/male-first-names.txt", mfnames_) &&
getLinesToVector("test/female-first-names.txt", ffnames_);
}
string getARandomStr(vector<string> const &strs) {
int n = rand() % strs.size() + 1;
return strs[n];
}
string getALName() { return getARandomStr(lnames_); }
string getAMFame() { return getARandomStr(mfnames_); }
string getAFFame() { return getARandomStr(ffnames_); }
int juliandate(int year, int month, int day) {
int a = (14 - month) / 12;
int m = month + 12 * a - 3;
int y = year + 4800 - a;
return day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 -
32045;
}
void calendardate(const int jdate, int &year, int &month, int &day) {
int a = jdate + 32044;
int b = (4 * a + 3) / 146097;
int c = a - 146097 * b / 4;
int d = (4 * c + 3) / 1461;
int e = c - 1461 * d / 4;
int m = (5 * e + 2) / 153;
day = e - (153 * m + 2) / 5 + 1;
month = m + 3 - 12 * (m / 10);
year = 100 * b + d - 4800 + m / 10;
}
struct Date {
int year;
int month;
int day;
};
string genRandomDate(const Date date1, const Date date2) {
int jdate1 = juliandate(date1.year, date1.month, date1.day);
int jdate2 = juliandate(date2.year, date2.month, date2.day);
int jdate = rand() % (jdate2 - jdate1 + 1) + jdate1;
Date date;
calendardate(jdate, date.year, date.month, date.day);
return to_string(date.year) + "-" + to_string(date.month) + "-" +
to_string(date.day);
}
string genAPerson(const size_t id) {
float r = ((double)rand() / (RAND_MAX));
string gender = r < 0.68 ? "male" : "female";
Date date1{1950, 1, 1}, date2{1999, 12, 31};
string date = genRandomDate(date1, date2);
string p = string("person{id:") + to_string(id) + ", gender:" + gender +
", last_name:'" + getALName() + "', first_name:'";
p += gender == "male" ? getAMFame() : getAFFame();
p += "',dob:'" + date + "'},";
return p;
}
void genPersonsThread(const int fromId, const int toId) {
string persons = genPersons(fromId, toId);
{
lock_guard<mutex> lg(readyMutex_);
resultStr_ += persons;
readyCount_--;
}
readyCV_.notify_one();
}
public:
Person() {
if (!initData())
throw "Failed init data";
}
string genPersons(const int fromId, const int toId) {
string persons = "";
for (int i = fromId; i <= toId; ++i) {
persons += genAPerson(i);
}
return persons;
}
string concGenPersons(const int fromId, const int toId) {
int num = toId - fromId + 1;
if (num < concurrency_ * 2)
return genPersons(fromId, toId);
{
lock_guard<mutex> lg(readyMutex_);
resultStr_ = "[";
readyCount_ = concurrency_;
}
int numPerCore = num / concurrency_;
vector<future<void>> futures;
for (int i = 0; i < concurrency_ - 1; ++i) {
futures.push_back(async(&Person::genPersonsThread, this,
numPerCore * i + 1, numPerCore * (i + 1)));
}
futures.push_back(async(&Person::genPersonsThread, this,
numPerCore * (concurrency_ - 1) + 1, toId));
{
unique_lock<mutex> ul(readyMutex_);
this->readyCV_.wait(ul, [this] { return readyCount_ == 0; });
}
resultStr_.pop_back();
return resultStr_ + "]";
// return dicts_;
}
};
/*
PREDICATE(conc_gen_persons, 3) {
srand(time(0));
int fromId((int)A1);
int toId((int)A2);
try {
Person p;
string dictsStr = p.concGenPersons(fromId, toId);
cout << "length:" << dictsStr.size() << endl;
A3 = (PlCompound)(dictsStr.c_str());
} catch (const exception &e) {
Utils::genPlException("conc_gen_persons_exception", string(e.what()));
} catch (...) {
Utils::genPlException("conc_gen_persons_exception",
string("unknown reason"));
}
return TRUE;
}
*/
int main() {
srand(time(0));
Person person;
auto start = steady_clock::now();
string persons = person.concGenPersons(1, 1000000);
auto end = steady_clock::now();
cout << "time used in milliseconds:"
<< duration_cast<milliseconds>(end - start).count() << endl;
return 0;
}
Any helps are greatly appreciated!
With best regards,
Arthur Wang