agra-uni-bremen / crave Goto Github PK
View Code? Open in Web Editor NEWConstrained random stimuli generation for C++ and SystemC
Home Page: http://systemc-verification.org/crave
License: Other
Constrained random stimuli generation for C++ and SystemC
Home Page: http://systemc-verification.org/crave
License: Other
I'm trying out the latest code in the development branch, using boost 1.57.0 on linux (Gentoo). When I run ex5_vec_constr, the produced output is (only the first 3 iterations are shown):
src_addr_vec = 28 8 12 4 0
dest_addr_vec = 8 16 24 32 40
data_vec = 4294901760 0 10 100 10 100 10 100 10 100src_addr_vec = 212 252 240 244 248 220 232 236 228 224
dest_addr_vec = 7 15 23 31 39 47 55 63 71 79
data_vec = 4294901760 0 10 100 10 100 10 100 10 100 10 100 10 100 10 100 10 100 10 100src_addr_vec = 20 24 28 8 12 4 0
dest_addr_vec = 12 20 28 36 44 52 60
data_vec = 4294901760 0 10 100 10 100 10 100 10 100 10 100 10 100
The printed elements have the following types:
crave::rand_vec<unsigned> src_addr_vec;
crave::rand_vec<unsigned> dest_addr_vec;
crave::rand_vec<unsigned> data_vec;
There seem to be a couple of issues with the generated values:
constraint(foreach (src_addr_vec(), src_addr_vec()[_i] < 0xFF));
constraint(foreach (src_addr_vec(), src_addr_vec()[_i] % 4 == 0));
constraint(unique(src_addr_vec()));
constraint(foreach (dest_addr_vec(), if_then(_i == 0, dest_addr_vec()[_i] < 0xF)));
constraint(foreach (dest_addr_vec(), dest_addr_vec()[_i] == dest_addr_vec()[_i - 1] + 8));
constraint(unique(dest_addr_vec()));
However, after randomizing the vector 100 times and inspecting the 1st element (index 0), it's clear that it's not uniformly randomly distributed between 0 & 14 at all. The only values assigned to it are 7, 8 and 11.
constraint(foreach (data_vec(), if_then_else(_i % 2 == 0, data_vec()[_i] <= 10,
data_vec()[_i] == data_vec()[_i - 1] * data_vec()[_i - 1])));
The 1st element (index 0) should be <= 10, which clearly isn't the case. For the 2nd element, the constraint matches, because static_cast(4294901760 โ 4294901760) == 0. Then for all the next elements, there's no randomness at all anymore.
I haven't been able to figure out from the code why this is happening, but I haven't had much time to look into it.
I have defined a constraint as shown below
Constraint: CHECK( crave::solve(x() >= 0, y() >= 0, x() * y() == 4 ));
The expected answer is x=2, y=2. But I am seeing values that are very different
Run1:
x y
1158303798 701293606
Run2:
x y
733933413 108964276
Please look into this issue. Any help regarding this will be really useful.
Creating an e.g. crave::randv<sc_dt::sc_bv<128>>
object works fine. However, when next()
is called on this object, only bits 0-63 will be set, the remaining ones will all be zero. This is hardcoded in SystemC.hpp's next
function, where an std::int64
generator is used.
I'm not sure how difficult it would be to fix this. Extending the random number generation to generate enough random bits seems doable. Modifying generated constraints to be correct seems like a more difficult task.
Alternatively, construction of such objects could be prevented with some SFINAE, e.g.:
/* Boost is preferred/required over C++14 for compatibility with e.g. QuestaSim. */
template <int N, std::enable_if_t<N <= 64, int> = 0>
struct randv<sc_dt::sc_bv<N>> : public randv_base<sc_dt::sc_bv<N>> { /* etc */ };
Hi,
I am trying to randomize the elements of a crv_vector depending on the value of a separate crv_variable. When trying to use a different crv_variable in the if-statement of the if-then-else construct, I am getting a segmentation fault. Using GDB, this fault is occurring at Line 48 of VectorGenerator.cpp (Line 48 if the accellera-contribution branch) and it seems like it is trying to dereference a NULL pointer.
How can I use a CRAVE variable ( crv_variable <enum_data_type> size ) in an if-then-else for a vector constraint for randomizing each vector element? See "c_len_vec" constraint below, specifically the last foreach loop.
c_num_mcs = {
num_mcs() >= 1,
if_then_else(
size() == TYPE_SIZE_LONG, //This works, and so we assumed that this would work for a vector (see below)
num_mcs() <= this->max_mcs_long,
num_mcs() <= this->max_mcs_short
)
};
c_len_vec = {
len_vec().size() == num_mcs(),
foreach(len_vec(), len_vec()[_i] >= 1),
//This foreach loop results in a segmentation fault.
foreach(len_vec(),
if_then_else(
size() == TYPE_SIZE_LONG, // This line results in a Segmentation Fault.
len_vec()[_i] <= this->max_mcs_len_long,
len_vec()[_i] <= this->max_mcs_len_short
)
)
};
I have two classes with simple public members, when I provide constraints which define dependency between classes, I dont see any randomization
e.g.
#include <crave/ConstrainedRandom.hpp>
#include <crave/experimental/Experimental.hpp>
#include <boost/format.hpp>
#include <iostream>
using namespace crave;
class class_a : public crv_sequence_item {
public:
crv_variable<unsigned int> num;
crv_constraint legal_num_class_C{ num() < 10 };
class_a(crave::crv_object_name name = "class_a") {
}
void print(){
std::cout<<" CLASS A num "<<num<<"\n";
}
};
class class_b : public crv_sequence_item {
public:
crv_variable<unsigned int> powr;
class_b(crave::crv_object_name name = "class_b") {
}
void print(){
std::cout<<" CLASS B POW "<<powr<<"\n";
}
};
int main(int argc, char* argv[]) {
crave::init("crave.cfg");
crave::set_global_seed(123456789);
class_a a("a");
class_b b("b");
crv_constraint legal_pow_class_{ b.powr() == (1<<a.num()) };
CHECK(a.randomize());
CHECK(b.randomize());
a.print();
b.print();
}
I get values of num and powr as zero when printed
CLASS A num 0
CLASS B POW 0
According to the C++ standard, it is not allowed to have identifiers containing double underscores anywhere in the name (paragraph 17.4.3.1.2), since all such identifiers are reserved. See also e.g. https://stackoverflow.com/questions/228783 or https://en.cppreference.com/w/cpp/language/identifiers (section "In declarations").
Most likely not an issue, but I figured I might as well mention it.
The (in)equality operators defined for crave::randv<sc_dt::sc_bv<W>>
behave asymmetrical once W > 64. Try for example the following code:
#include <crave/ConstrainedRandom.hpp>
#include <crave/SystemC.hpp>
#include <systemc>
#include <iomanip>
#include <iostream>
int sc_main (int argc, char ** argv) {
std::uint64_t const c_IntOnes = ~(0ull);
sc_dt::sc_bv<128> const c_BvOnes = ~sc_dt::sc_bv<128>(0);
auto largeBv = crave::randv<sc_dt::sc_bv<128>>(nullptr);
largeBv = c_BvOnes;
std::cout << "c_IntOnes = 0x" << std::hex << c_IntOnes << std::dec << "\n";
std::cout << "largeBv = 0b" << largeBv << "\n";
std::cout << "\n";
std::cout << std::boolalpha;
std::cout << "(largeBv == c_IntOnes) = " << static_cast<bool>(largeBv == c_IntOnes) << "\n";
std::cout << "(c_IntOnes == largeBv) = " << static_cast<bool>(c_IntOnes == largeBv) << "\n";
std::cout << "\n";
return 0;
}
The cause seems to be the promotion of c_IntOnes
to sc_dt::int64
when calling operator== (sc_dt::int64 const, randv<Typename<N>> const &)
. I tried my hand at fixing the RANDV_SCDT_BINARY_OPERATOR
macro, but so far haven't been able to come up with the proper SFINAE to make it work/compile in all cases.
Also note that these (in)equality operators all return sc_dt::int64
instead of bool
.
I have successfully built CRAVE using the default build with the Boolector and CUDD solvers. I can build and run most of the examples except either of the sudoku ones. Is the selection of Boolector and CUDD solvers capable of solving the constraints for these sudoku examples? The examples will start simulating, but then go on for hours without finishing.
Thanks,
Peter
When a crave::randv
object is constructed with a non-nullptr
value for the parent
pointer, it registers itself with said parent (through randv_base::add_base_child
). However, upon destruction it doesn't deregister itself from the parent. This causes dangling pointers and the undefined behavior that comes with it when rand_base::next()
is called on the parent (so far I've seen SIGSERV and "abstract virtual called").
Furthermore, since there's copy constructors defined for the randv_base
and randv
types, move construction and assignment are both implicitly disabled. Just "thinking out loud", it seems to me that when a parent class is moved, it should be able to call some sort of "move_parent()" on the randv
child objects. Such move_parent
functionality would be the equivalent of remove_base_child
(which currently doesn't exist) followed by add_base_child
. This move_parent
could then also be called by a user's custom objects where appropriate.
Similar things can most likely be said about rand_obj
and its add_obj_child
function (although I didn't check this thoroughly yet).
Below is a minimalistic example that triggers UB through derefencing pointers to destructed objects. I know crave::rand_vec
exists, but I don't see why this example using std::vector
shouldn't be able to work if the above issues are solved.
#include <crave/ConstrainedRandom.hpp>
#include <cstdint>
#include <iostream>
#include <vector>
struct custom_item : public crave::rand_obj {
using base_type = crave::rand_obj;
custom_item (crave::rand_obj * parent = nullptr)
: base_type(parent), vectorSize_(this)
{
constraint(0 < vectorSize_() && vectorSize_() <= 10);
}
virtual bool next () override {
bool const result = base_type::next();
post_randomize();
return result;
}
virtual void post_randomize () {
items_.clear();
items_.reserve(vectorSize_);
for (std::size_t count = 0; count < vectorSize_; ++count) {
items_.emplace_back(this);
items_.back().next();
}
}
crave::randv<std::size_t> vectorSize_;
std::vector<crave::randv<int>> items_ = {};
};
std::ostream & operator<< (std::ostream & os, custom_item const & obj) {
os << "elements [" << obj.vectorSize_ << "]: ";
for (auto const & entry : obj.items_) { os << entry << ' '; }
return os;
}
int main () {
crave::init("crave.cfg");
crave::set_global_seed(1234567890); // Raises SIGSERV.
//crave::set_global_seed(2234567890); // Raises abstract virtual called.
custom_item anItem;
for (int i = 0; i < 5; i++) {
CHECK(anItem.next());
std::cout << anItem << '\n';
}
}
Just a question: am i correct in assuming that crave is not thread safe, i.e. it's not possible to create random stimuli from multiple linux thread contexts in parallel even if those threads have their own private rand_obj's to manage?
Thanks!
I set_global_seed to 0 and run multiple times, and eventually hit a failure in my test. How can I know what seed was used for that test?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.