-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathPerformanceTest.cpp
176 lines (141 loc) · 5.96 KB
/
PerformanceTest.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//
// PerformanceTest.cpp - Simple random performance test which can be
// run against the DirectedAcyclicGraph or its boost wrapper
// equivalent. Uses the boost POSIX time library because <ctime.h>
// can't add time intervals.
//
// Copyright (c) 2009 HostileFork.com
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://hostilefork.com/nocycle for documentation.
//
// I use boost::posix_time for timing functions, if you don't want to use
// boost then this has to be turned off
#define RECORD_TIME_DURATIONS 0
// If you want to use the boost adjacency_matrix implementation instead of
// Nocycle's OrientedGraph-based implementation, set to 1. Probably won't
// work for > 12K nodes
#define USE_BOOST_GRAPH_IMPLEMENTATION 0
// Some regression tests require boost to be included in your library path
// so make sure you've turned off the self tests (NSTATE_SELFTEST,
// ORIENTEDGRAPH_SELFTEST, DIRECTEDACYCLICGRAPH_SELFTEST) if you don't want
// to build with boost
#define REGRESSION_TESTS 0
const unsigned NUM_TEST_NODES = /* 65536 + 1024 */ 1024;
const unsigned NUM_TEST_ITERATIONS = NUM_TEST_NODES*2;
const float REMOVE_PROBABILITY = 1.0/8.0;
#include <iostream>
#include "Nstate.hpp"
//#include "nstate/Nstate.hpp"
#include "OrientedGraph.hpp"
#include "DirectedAcyclicGraph.hpp"
#include "RandomEdgePicker.hpp"
#include <set>
#include <map>
#if RECORD_TIME_DURATIONS
#include "boost/date_time/posix_time/posix_time.hpp"
#endif
#if USE_BOOST_GRAPH_IMPLEMENTATION
#include "BoostImplementation.hpp"
typedef nocycle::RandomEdgePicker<nocycle::BoostDirectedAcyclicGraph> DAGType;
#else
typedef nocycle::RandomEdgePicker<nocycle::DirectedAcyclicGraph> DAGType;
#endif
int main (int argc, char * const argv[]) {
#if RECORD_TIME_DURATIONS
boost::posix_time::time_duration addTime = boost::posix_time::seconds(0);
boost::posix_time::time_duration removeTime = boost::posix_time::seconds(0);
#endif
#if REGRESSION_TESTS && NSTATE_SELFTEST
if (nocycle::Nstate<3>::SelfTest()) {
std::cout << "SUCCESS: All Nstate SelfTest() passed regression." << std::endl;
} else {
return 1;
}
if (nocycle::NstateArray<3>::SelfTest()) {
std::cout << "SUCCESS: All NstateArray SelfTest() passed regression." << std::endl;
} else {
return 1;
}
#endif
#if REGRESSION_TESTS && ORIENTEDGRAPH_SELFTEST
if (nocycle::OrientedGraph::SelfTest()) {
std::cout << "SUCCESS: All OrientedGraph SelfTest() passed regression." << std::endl;
} else {
return 1;
}
#endif
#if REGRESSION_TESTS && DIRECTEDACYCLICGRAPH_SELFTEST
if (nocycle::DirectedAcyclicGraph::SelfTest()) {
std::cout << "SUCCESS: All DirectedAcyclicGraph SelfTest() passed regression." << std::endl;
} else {
return 1;
}
#endif
unsigned numCyclesCaught = 0;
unsigned numInsertions = 0;
unsigned numDeletions = 0;
DAGType dag (NUM_TEST_NODES);
for (DAGType::VertexID vertex = 0; vertex < NUM_TEST_NODES; vertex++) {
dag.CreateVertex(vertex);
}
// keep adding random vertices and make sure that if it causes a cycle exception on the boost
// implemented class, that it also causes a cycle exception on the non-boost class
for (unsigned index = 0; index < NUM_TEST_ITERATIONS; index++) {
DAGType::VertexID vertexSource;
DAGType::VertexID vertexDest;
bool removeEdge = (dag.NumEdges() > 0) && ((rand() % 10000) < (REMOVE_PROBABILITY * 10000));
if (removeEdge) {
// We don't count the time for picking the vertex in the performance evaluation
dag.GetRandomEdge(vertexSource, vertexDest);
std::cout << "dag.RemoveEdge(" << vertexSource << ", " << vertexDest << ")";
// We want to be twice as likely to pick a vertex with 2 outgoing connections as 1,
// and three times as likely to pick a vertex with 3 outgoing connections... etc.
// Vertices with 0 outgoing connections will not be picked!
#if RECORD_TIME_DURATIONS
boost::posix_time::ptime timeStart = boost::posix_time::microsec_clock::local_time();
#endif
dag.RemoveEdge(vertexSource, vertexDest);
#if RECORD_TIME_DURATIONS
boost::posix_time::time_duration timeDuration = (boost::posix_time::microsec_clock::local_time() - timeStart);
removeTime += timeDuration;
std::cout << " : " << timeDuration;
#endif
std::cout << std::endl;
numDeletions++;
} else {
dag.GetRandomNonEdge(vertexSource, vertexDest);
std::cout << "dag.AddEdge(" << vertexSource << ", " << vertexDest << ")";
#if RECORD_TIME_DURATIONS
boost::posix_time::ptime timeStart = boost::posix_time::microsec_clock::local_time();
#endif
bool causedCycle = false;
try {
dag.AddEdge(vertexSource, vertexDest);
} catch (nocycle::bad_cycle& e) {
causedCycle = true;
}
#if RECORD_TIME_DURATIONS
boost::posix_time::time_duration timeDuration = (boost::posix_time::microsec_clock::local_time() - timeStart);
addTime += timeDuration;
std::cout << " : " << timeDuration;
#endif
if (causedCycle) {
std::cout << " ==> !!!CYCLE!!! ";
numCyclesCaught++;
} else {
numInsertions++;
}
std::cout << std::endl;
}
}
std::cout << "NOTE: Inserted " << numInsertions << ", Deleted " << numDeletions << ", and Caught " << numCyclesCaught << " cycles." << std::endl;
#if RECORD_TIME_DURATIONS
std::cout << "NOTE: Total AddEdge time = " << addTime << std::endl;
std::cout << "NOTE: Total RemoveEdge time = " << removeTime << std::endl;
#endif
return 0;
}