8 #include <sys/resource.h>
10 #include <boost/tuple/tuple_io.hpp>
12 #include <opencog/util/oc_assert.h>
13 #include <opencog/util/random.h>
31 using namespace boost;
39 #define DIVIDER_LINE "------------------------------"
40 #define PROGRESS_BAR_LENGTH 10
49 atomCount = (1 << 18);
50 defaultNodeType = CONCEPT_NODE;
51 chanceOfNonDefaultNode = 0.4f;
52 defaultLinkType = INHERITANCE_LINK;
53 chanceOfNonDefaultLink = 0.4f;
55 prg =
new std::poisson_distribution<unsigned>(linkSize_mean);
58 showTypeSizes =
false;
66 buildTestData =
false;
67 chanceUseDefaultTV = 0.8f;
71 randomseed = (
unsigned long) time(NULL);
115 total =
sizeof(
Node);
116 total += n->getName().capacity();
121 total =
sizeof(
Link);
122 total += l->getOutgoingSet().capacity() *
sizeof(
Handle);
123 for (
Handle ho: l->getOutgoingSet())
125 total += estimateOfAtomSize(ho);
137 struct rusage *s = (
struct rusage *) malloc(
sizeof(
struct rusage));
138 getrusage(RUSAGE_SELF,s);
139 long rss = s->ru_maxrss;
149 cout <<
"==sizeof() on various classes==" << endl;
150 cout <<
"FIXME: the report below is only for the sizes of the C++ objects\n"
151 <<
"themselves. In addition, every atom consumes from 5 to 15 times\n"
152 <<
"the sizeof(Handle) in the AtomTable indexes. This depends on the\n"
153 <<
"atom type; Links store more than twice the the sizeof(Handle) per\n"
154 <<
"outgoing atoms.\n";
155 cout <<
"Type = " <<
sizeof(
Type) << endl;
156 cout <<
"Handle = " <<
sizeof(
Handle) << endl;
157 cout <<
"Atom = " <<
sizeof(
Atom) << endl;
158 cout <<
"Node = " <<
sizeof(
Node) << endl;
159 cout <<
"Link = " <<
sizeof(
Link) << endl;
164 cout <<
"IncomingSet = " <<
sizeof(
IncomingSet) << endl;
165 cout <<
"AtomSignal = " <<
sizeof(
AtomSignal) << endl;
169 #define ND(T,S) ({Handle n(createNode(T,S)); n;})
170 #define LK(T,A,B) ({Handle l(createLink(T,A,B)); l;})
171 Handle h =
ND(CONCEPT_NODE,
"this is a test");
172 cout <<
"ConceptNode \"this is a test\" = "
173 << estimateOfAtomSize(h) << endl;
177 cout <<
"Empty ListLink = " << estimateOfAtomSize(h) << endl;
179 Handle na =
ND(CONCEPT_NODE,
"first atom");
180 Handle nb =
ND(CONCEPT_NODE,
"second atom");
182 cout <<
"ListLink with two ConceptNodes = "
183 << estimateOfAtomSize(ll) << endl;
185 Handle np =
ND(PREDICATE_NODE,
"some predicate");
186 Handle el =
LK(EVALUATION_LINK, np, ll);
187 cout <<
"EvaluationLink with two ConceptNodes = "
188 << estimateOfAtomSize(el) << endl;
193 cout <<
"Methods that can be tested:" << endl;
194 cout <<
" addNode" << endl;
195 cout <<
" addLink" << endl;
196 cout <<
" removeAtom" << endl;
197 cout <<
" getType" << endl;
198 cout <<
" getTruthValue" << endl;
199 cout <<
" setTruthValue" << endl;
200 #ifdef ZMQ_EXPERIMENT
201 cout <<
" getTruthValueZMQ" << endl;
203 cout <<
" getHandlesByType" << endl;
204 cout <<
" getOutgoingSet" << endl;
205 cout <<
" getIncomingSet" << endl;
210 bool foundMethod =
false;
212 if (methodToTest ==
"all" || methodToTest ==
"noop") {
214 methodNames.push_back(
"noop");
218 if (methodToTest ==
"all" || methodToTest ==
"addNode") {
220 methodNames.push_back(
"addNode");
224 if (methodToTest ==
"all" || methodToTest ==
"addLink") {
226 methodNames.push_back(
"addLink");
230 if (methodToTest ==
"all" || methodToTest ==
"removeAtom") {
232 methodNames.push_back(
"removeAtom");
236 if (methodToTest ==
"all" || methodToTest ==
"getType") {
238 methodNames.push_back(
"getType");
242 if (methodToTest ==
"all" || methodToTest ==
"getTruthValue") {
244 methodNames.push_back(
"getTruthValue");
248 #ifdef ZMQ_EXPERIMENT
249 if (methodToTest ==
"all" || methodToTest ==
"getTruthValueZMQ") {
250 methodsToTest.push_back( &AtomSpaceBenchmark::bm_getTruthValueZmq);
251 methodNames.push_back(
"getTruthValueZMQ");
256 if (methodToTest ==
"all" || methodToTest ==
"setTruthValue") {
258 methodNames.push_back(
"setTruthValue");
262 if (methodToTest ==
"all" || methodToTest ==
"getHandlesByType") {
264 methodNames.push_back(
"getHandlesByType");
268 if (methodToTest ==
"all" || methodToTest ==
"getOutgoingSet") {
270 methodNames.push_back(
"getOutgoingSet");
274 if (methodToTest ==
"all" || methodToTest ==
"getIncomingSet") {
276 methodNames.push_back(
"getIncomingSet");
281 std::cerr <<
"Error: specified a bad test name: " << methodToTest << std::endl;
287 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
291 clock_t sumAsyncTime = 0;
293 std::vector<record_t> records;
294 cout <<
"Benchmarking ";
296 case BENCH_AS: cout <<
"AtomSpace's ";
break;
297 case BENCH_TABLE: cout <<
"AtomTable's ";
break;
299 case BENCH_SCM: cout <<
"Scheme's ";
300 if (memoize) cout <<
"memoized ";
301 else if (compile) cout <<
"compiled ";
302 else cout <<
"interpreted ";
306 case BENCH_PYTHON: cout <<
"Python's ";
break;
309 cout << methodName <<
" method " << (Nreps*Nloops) <<
" times ";
310 std::ofstream myfile;
313 myfile.open ((methodName +
"_benchmark.csv").c_str());
318 rssStart = getMemUsage();
319 long rssFromIncrease = 0;
321 gettimeofday(&tim, NULL);
322 double t1 = tim.tv_sec + (tim.tv_usec/1000000.0);
323 for (
unsigned int i=0; i < Nreps; i++)
327 long rssBeforeIncrease = getMemUsage();
328 buildAtomSpace(sizeIncrease, percentLinks,
false);
330 rssFromIncrease += (getMemUsage() - rssBeforeIncrease);
332 size_t atomspaceSize;
333 if (testKind == BENCH_TABLE)
334 atomspaceSize = atab->getSize();
336 atomspaceSize = asp->get_size();
338 sumAsyncTime += get<0>(timeTaken);
340 if (saveInterval && counter % saveInterval == 0)
343 record_t dataPoint(atomspaceSize,get<0>(timeTaken),getMemUsage()-rssStart-rssFromIncrease);
347 if (get<0>(timeTaken) < 0) cout <<
"ftumf" << endl;
348 records.push_back(dataPoint);
351 if (saveToFile) recordToFile(myfile,dataPoint);
353 if (i % diff == 0) cerr <<
"." << flush;
355 Handle rh = getRandomHandle();
356 gettimeofday(&tim, NULL);
357 double t2=tim.tv_sec+(tim.tv_usec/1000000.0);
358 printf(
"\n%.6lf seconds elapsed (%.2f per second)\n", t2-t1, 1.0f/((t2-t1)/Nreps));
360 cout <<
"Sum clock() time for all requests: " << sumAsyncTime <<
" (" <<
361 (float) sumAsyncTime / CLOCKS_PER_SEC <<
" seconds, "<<
362 1.0f/(((
float)sumAsyncTime/CLOCKS_PER_SEC) / (Nreps*Nloops)) <<
" requests per second)" << endl;
366 if (saveInterval && doStats)
374 if (saveToFile) { myfile.close(); }
379 cout <<
"OpenCog Atomspace Benchmark - " <<
VERSION_STRING <<
"\n";
380 cout <<
"\nRandom generator: MT19937\n";
381 cout <<
"Random seed: " << randomseed <<
"\n\n";
387 rng =
new opencog::MT19937RandGen(randomseed);
391 prg =
new std::poisson_distribution<unsigned>(linkSize_mean);
394 if (showTypeSizes) printTypeSizes();
396 for (
unsigned int i = 0; i < methodNames.size(); i++) {
399 if (testKind == BENCH_TABLE) {
404 cogs =
new CogServer();
405 if (pymo == NULL) pymo =
new PythonModule(*cogs);
407 asp = &cogs->getAtomSpace();
416 std::ostringstream dss;
417 dss <<
"from opencog.atomspace import AtomSpace, types, Handle, TruthValue\n"
418 <<
"aspace = AtomSpace(" << asp <<
")\n";
419 pyev->eval(dss.str());
429 if (buildTestData) buildAtomSpace(atomCount, percentLinks,
false);
432 doBenchmark(methodNames[i], methodsToTest[i]);
434 if (testKind == BENCH_TABLE)
456 std::ostringstream dss;
457 dss <<
"(define (mk) " << exp <<
")\n";
458 scm->eval(dss.str());
463 std::ostringstream dss;
464 dss <<
"(compile '(define (mk) " << exp
465 <<
") #:env (current-module))\n";
466 scm->eval(dss.str());
473 std::ostringstream dss;
474 dss <<
"def mk():\n" << exp <<
"\n\n";
475 pyev->eval(dss.str());
485 OC_ASSERT(t < numberOfTypes);
492 candidateType = ATOM + rng->randint(numberOfTypes-1);
496 candidateType == NUMBER_NODE or
497 candidateType == TYPE_NODE);
499 return candidateType;
507 bool useDefaultTV = (rng->randfloat() < chanceUseDefaultTV);
510 if (not useDefaultTV) {
511 float strength = rng->randfloat();
512 float conf = rng->randfloat();
517 double p = rng->randdouble();
518 Type t = defaultNodeType;
519 if (p < chanceOfNonDefaultNode)
520 t = randomType(NODE);
522 std::string scp(csi);
523 if (csi.size() == 0) {
524 std::ostringstream oss;
526 if (NUMBER_NODE == t)
529 oss <<
"node " << counter;
535 clock_t t_begin = clock();
537 return clock() - t_begin;
540 clock_t t_begin = clock();
541 asp->add_node(t, scp);
542 return clock() - t_begin;
546 std::ostringstream ss;
547 for (
unsigned int i=0; i<Nloops; i++) {
548 ss <<
"(cog-new-node '"
550 <<
" \"" << scp <<
"\")\n";
552 p = rng->randdouble();
554 if (p < chanceOfNonDefaultNode)
555 t = randomType(NODE);
558 if (csi.size() == 0) {
559 std::ostringstream oss;
561 if (NUMBER_NODE == t)
564 oss <<
"node " << counter;
568 std::string gs = memoize_or_compile(ss.str());
570 clock_t t_begin = clock();
572 return clock() - t_begin;
578 std::ostringstream dss;
579 for (
unsigned int i=0; i<Nloops; i++) {
580 if (memoize) dss <<
" ";
581 dss <<
"aspace.add_node (" << t <<
", \"" << scp <<
"\")\n";
583 p = rng->randdouble();
585 if (p < chanceOfNonDefaultNode)
586 t = randomType(NODE);
589 if (csi.size() == 0) {
590 std::ostringstream oss;
592 if (NUMBER_NODE == t)
595 oss <<
"node " << counter;
599 std::string ps = memoize_or_compile(dss.str());
600 clock_t t_begin = clock();
602 return clock() - t_begin;
612 Type t = defaultLinkType;
613 double p = rng->randdouble();
614 if (p < chanceOfNonDefaultLink) t = randomType(LINK);
616 size_t arity = (*prg)(randgen);
617 if (arity == 0) { ++arity; };
620 if (CONTEXT_LINK == t) arity = 2;
623 for (
size_t j=0; j < arity; j++) {
624 Handle h(getRandomHandle());
625 outgoing.push_back(h);
631 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
632 std::ostringstream dss;
633 dss <<
"aspace.add_link (" << t <<
", [";
634 for (
size_t j=0; j < arity; j++) {
635 dss <<
"Handle( " << outgoing[j].value() <<
")";
636 if (j < arity-1) dss <<
", ";
639 std::string ps = dss.str();
640 clock_t t_begin = clock();
642 return clock() - t_begin;
653 std::ostringstream ss;
654 for (
unsigned int i=0; i<Nloops; i++) {
655 if (25 < arity) arity = 25;
656 for (
size_t j = 0; j < arity; j++) {
658 ss <<
"(define h" << c
659 <<
" (cog-atom " << outgoing[j].value() <<
"))\n";
661 ss <<
"(cog-new-link '"
663 for (
size_t j = 0; j < arity; j++) {
670 p = rng->randdouble();
671 if (p < chanceOfNonDefaultLink) t = randomType(LINK);
673 arity = (*prg)(randgen);
674 if (arity == 0) { ++arity; };
677 if (CONTEXT_LINK == t) arity = 2;
680 for (
size_t j=0; j < arity; j++) {
681 outgoing.push_back(getRandomHandle());
684 std::string gs = memoize_or_compile(ss.str());
686 clock_t t_begin = clock();
688 return clock() - t_begin;
692 clock_t tAddLinkStart = clock();
694 return clock() - tAddLinkStart;
697 clock_t tAddLinkStart = clock();
698 asp->add_link(t, outgoing);
699 return clock() - tAddLinkStart;
708 if (testKind == BENCH_PYTHON)
712 if (testKind == BENCH_SCM)
716 clock_t tStart = clock();
718 cout <<
"Building atomspace with " << atomspaceSize <<
" atoms (" <<
719 _percentLinks*100.0 <<
"\% links)" << endl;
723 long nodeCount = atomspaceSize * (1.0f - _percentLinks);
725 if (display) cout <<
"Adding " << nodeCount <<
" nodes ";
728 for (i=0; i<nodeCount; i++) {
730 if (display && i % diff == 0) cerr <<
"." << flush;
735 if (display) cout << endl <<
"Adding " << atomspaceSize - nodeCount <<
" links " << flush;
738 for (; i < atomspaceSize; i++) {
740 if (display && (i-nodeCount) % diff == 0) { cerr <<
"." << flush; }
745 printf(
"Built atomspace, execution time: %.2fs\n",
746 (
double)(clock() - tStart)/CLOCKS_PER_SEC);
760 time_taken = clock() - t_begin;
778 Handle h = getRandomHandle();
783 h = getRandomHandle();
790 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
791 std::ostringstream dss;
792 for (
unsigned int i=0; i<Nloops; i++) {
793 dss <<
"aspace.remove(Handle(" << h.
value() <<
"))\n";
794 h = getRandomHandle();
798 h = getRandomHandle();
801 std::string ps = dss.str();
802 clock_t t_begin = clock();
804 return clock() - t_begin;
809 std::ostringstream ss;
810 for (
unsigned int i=0; i<Nloops; i++) {
811 ss <<
"(cog-delete-recursive (cog-atom " << h.
value() <<
"))\n";
812 h = getRandomHandle();
816 h = getRandomHandle();
819 std::string gs = memoize_or_compile(ss.str());
821 clock_t t_begin = clock();
823 time_taken = clock() - t_begin;
830 time_taken = clock() - t_begin;
836 time_taken = clock() - t_begin;
844 Handle h(UUID_begin + rng->randint(UUID_end-1-UUID_begin));
847 while (NULL == h.operator->()) {
848 h = getRandomHandle();
855 Handle h = getRandomHandle();
861 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
862 std::ostringstream dss;
863 for (
unsigned int i=0; i<Nloops; i++) {
864 dss <<
"aspace.get_type(Handle(" << h.
value() <<
"))\n";
865 h = getRandomHandle();
867 std::string ps = dss.str();
868 clock_t t_begin = clock();
870 return clock() - t_begin;
875 std::ostringstream ss;
876 for (
unsigned int i=0; i<Nloops; i++) {
877 ss <<
"(cog-type (cog-atom " << h.
value() <<
"))\n";
878 h = getRandomHandle();
880 std::string gs = memoize_or_compile(ss.str());
882 clock_t t_begin = clock();
884 time_taken = clock() - t_begin;
891 time_taken = clock() - t_begin;
897 time_taken = clock() - t_begin;
905 Handle h = getRandomHandle();
911 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
912 std::ostringstream dss;
913 dss <<
"aspace.get_tv(Handle(" << h.
value() <<
"))\n";
914 std::string ps = dss.str();
915 clock_t t_begin = clock();
917 return clock() - t_begin;
922 std::ostringstream ss;
923 for (
unsigned int i=0; i<Nloops; i++) {
924 ss <<
"(cog-tv (cog-atom " << h.
value() <<
"))\n";
925 h = getRandomHandle();
927 std::string gs = memoize_or_compile(ss.str());
929 clock_t t_begin = clock();
931 time_taken = clock() - t_begin;
938 time_taken = clock() - t_begin;
944 time_taken = clock() - t_begin;
950 #ifdef ZMQ_EXPERIMENT
951 timepair_t AtomSpaceBenchmark::bm_getTruthValueZmq()
953 Handle h = getRandomHandle();
954 clock_t t_begin = clock();
956 return clock() - t_begin;
962 Handle h = getRandomHandle();
964 float strength = rng->randfloat();
965 float conf = rng->randfloat();
972 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
973 std::ostringstream dss;
974 dss <<
"aspace.set_tv(Handle(" << h.
value()
975 <<
"), TruthValue(" << strength <<
", " << conf <<
"))\n";
976 std::string ps = dss.str();
977 clock_t t_begin = clock();
979 return clock() - t_begin;
984 std::ostringstream ss;
985 for (
unsigned int i=0; i<Nloops; i++) {
986 ss <<
"(cog-set-tv! (cog-atom " << h.
value() <<
")"
987 <<
" (cog-new-stv " << strength <<
" " << conf <<
")"
990 h = getRandomHandle();
991 strength = rng->randfloat();
992 conf = rng->randfloat();
994 std::string gs = memoize_or_compile(ss.str());
996 clock_t t_begin = clock();
998 time_taken = clock() - t_begin;
1006 time_taken = clock() - t_begin;
1013 time_taken = clock() - t_begin;
1021 Type t = randomType(ATOM);
1024 case BENCH_PYTHON: {
1025 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
1026 std::ostringstream dss;
1027 dss <<
"aspace.get_atoms_by_type(" << t <<
", True)\n";
1028 std::string ps = dss.str();
1029 clock_t t_begin = clock();
1031 return clock() - t_begin;
1041 clock_t t_begin = clock();
1043 asp->get_handles_by_type(results, t,
true);
1044 clock_t time_taken = clock() - t_begin;
1049 clock_t t_begin = clock();
1050 asp->get_handles_by_type(back_inserter(results), t,
true);
1051 clock_t time_taken = clock() - t_begin;
1059 Handle h = getRandomHandle();
1064 case BENCH_PYTHON: {
1065 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
1066 std::ostringstream dss;
1067 dss <<
"aspace.get_outgoing(Handle(" << h.
value() <<
"))\n";
1068 std::string ps = dss.str();
1069 clock_t t_begin = clock();
1071 return clock() - t_begin;
1076 std::ostringstream ss;
1077 for (
unsigned int i=0; i<Nloops; i++) {
1078 ss <<
"(cog-outgoing-set (cog-atom " << h.
value() <<
"))\n";
1079 h = getRandomHandle();
1081 std::string gs = memoize_or_compile(ss.str());
1083 clock_t t_begin = clock();
1085 time_taken = clock() - t_begin;
1092 if (l) l->getOutgoingSet();
1093 time_taken = clock() - t_begin;
1098 asp->get_outgoing(h);
1099 time_taken = clock() - t_begin;
1107 Handle h = getRandomHandle();
1112 case BENCH_PYTHON: {
1113 OC_ASSERT(1 == Nloops,
"Looping not supported for python");
1114 std::ostringstream dss;
1115 dss <<
"aspace.get_incoming(Handle(" << h.
value() <<
"))\n";
1116 std::string ps = dss.str();
1117 clock_t t_begin = clock();
1119 return clock() - t_begin;
1124 std::ostringstream ss;
1125 for (
unsigned int i=0; i<Nloops; i++) {
1126 ss <<
"(cog-incoming-set (cog-atom " << h.
value() <<
"))\n";
1127 h = getRandomHandle();
1129 std::string gs = memoize_or_compile(ss.str());
1131 clock_t t_begin = clock();
1133 time_taken = clock() - t_begin;
1140 time_taken = clock() - t_begin;
1145 asp->get_incoming(h);
1146 time_taken = clock() - t_begin;
1153 const std::vector<record_t>& records)
1159 sum += get<1>(record);
1160 if (get<1>(record) > t_max) t_max = get<1>(record);
1161 if (get<1>(record) < t_min) t_min = get<1>(record);
1164 t_N = records.size();
1168 clock_t value = (get<1>(record) - t_mean);
1169 sum += (value*value);
1171 t_std = sqrt(sum/(t_N-1));
1176 cout <<
"Per operation stats, in CPU clock ticks: " << endl;
1177 cout <<
" N: " << t_N << endl;
1178 cout <<
" mean: " << t_mean << endl;
1179 cout <<
" min: " << t_min << endl;
1180 cout <<
" max: " << t_max << endl;
1181 cout <<
" std: " << t_std << endl;
1186 myfile << tuples::set_open(
' ');
1187 myfile << tuples::set_close(
' ');
1188 myfile << tuples::set_delimiter(
',');
1190 myfile <<
"," << (float) get<1>(record) / CLOCKS_PER_SEC << endl;
AttentionValuePtr getAttentionValue()
a TruthValue that stores a mean and the number of observations (strength and confidence) ...
#define PROGRESS_BAR_LENGTH
IncomingSet getIncomingSet()
std::string memoize_or_compile(std::string)
std::vector< Handle > HandleSeq
a list of handles
std::shared_ptr< TruthValue > TruthValuePtr
static UUID getMaxUUID(void)
void recordToFile(std::ofstream &file, const record_t record) const
void buildAtomSpace(long atomspaceSize=(1<< 16), float percentLinks=0.1, bool display=true)
boost::signals2::signal< void(AtomPtr, LinkPtr)> AtomPairSignal
std::shared_ptr< Link > LinkPtr
boost::tuple< size_t, clock_t, long > record_t
void setTruthValue(TruthValuePtr)
Sets the TruthValue object of the atom.
ClassServer & classserver(ClassServerFactory *=ClassServer::createInstance)
static NodePtr NodeCast(const Handle &h)
static PythonEval & instance(AtomSpace *atomspace=NULL)
const char * VERSION_STRING
Type getNumberOfClasses()
void setMethod(std::string method)
static TruthValuePtr createTV(strength_t mean, count_t count)
static TruthValuePtr DEFAULT_TV()
const std::string & getTypeName(Type type)
static LinkPtr LinkCast(const Handle &h)
boost::signals2::signal< void(const Handle &)> AtomSignal
std::vector< LinkPtr > IncomingSet
void startBenchmark(int numThreads=1)
static AttentionValuePtr DEFAULT_AV()
to be used as default attention value
std::shared_ptr< Node > NodePtr
timepair_t bm_getOutgoingSet()
TruthValuePtr getTruthValue()
clock_t makeRandomNode(const std::string &s)
TimeStats(const std::vector< record_t > &records)
unsigned short Type
type of Atoms, represented as short integer (16 bits)
void doBenchmark(const std::string &methodName, BMFn methodToCall)
size_t getIncomingSetSize()
Get the size of the incoming set.
timepair_t bm_getHandlesByType()
#define CALL_MEMBER_FN(object, ptrToMember)
a TruthValue that stores a mean, a confidence and the number of observations
size_t estimateOfAtomSize(Handle h)
timepair_t bm_getIncomingSet()
timepair_t bm_getTruthValue()
timepair_t bm_setTruthValue()
boost::tuple< clock_t, clock_t > timepair_t