Ler esse documento em português
Third iteration of the Simulator of Non-Uniform Cache Architectures.
SiNUCA3 is developed by the following students of Dr. Marco Zanata:
- Gabriel G. de Brito
- Vinícius Santos
- Fernando de Barros Castro
- Bruno Krügel
- Daniel Siqueira
- Pedro Endrigo dos Santos
- Giuliano Tavares
SiNUCA3 depends on libyaml (sudo apt install libyaml-dev on Debian, Ubuntu and
derivatives).
Just make works.
We use a Makefile that automatically detects every source file in src/ and
builds it to it's own object to build/, linking everything together as
sinuca3. Also, it'll use clang if you have it installed, but will fallback
to gcc or cc otherwise.
That said, you can build an optimized binary by just running "make" and a debug binary by running "make debug". Both can coexist as the object names and the binaries are different (debug ones have -debug appended to the name).
If you play with any header file, you'll unfortunatelly have to make -B
because our build system does not automatically rebuilds sources when their
headers have changed.
SiNUCA3 instantiates a system by reading YAML configuration files. Example
files are provided in config_files/. The system simulates the execution of
instructions from trace files.
One starts the simulator as:
./sinuca3 -c <config file> -d <trace directory> -t <trace name>To generate traces, refer to each architecture tracer documentation.
Configuration files define the system in terms of components. In modern
pipelined architectures, a component will usually simulate the behaviour of a
specific part of a pipeline stage. During the simulation, a component runs it's
Clock method each cycle, and it can read and send messages from other
components.
As said in building, you can just throw a .cpp or .c file inside src/ and
it'll be picked up by the build system. For creating your own components, it may
be a good idea to keep things organized and put them into the
src/custom_components/ directory.
You'll need to add your custom components to the
src/custom_components/custom.cpp file also.
Most of the API is accessible via sinuca3.hpp.
Simulation components are loosely defined as a stage of the pipeline. They
communicate via a message passing interface. Each cycle, a component can read
messages send to it by other components in the previous cycle. To create a
component, one's need to inherit from Component<T>, whereas T is the type of
message it receives.
To simulate a system, define it in a yaml configuration file.
When needing to actually reuse code, prefer to compose, I.e, add the specific class as a private attribute and call it's methods.
We like to use modern tools like clangd and lldb and old standards: our C++
is C++98 and our C is C99. When adding new files, please be kind and run bear --append -- make debug so clangd properly detects them. After editing, please
format everything with clang-format. A common trick is to run find . -type f -name "*.[cpp,hpp,c,h]" -exec clang-format -i {} \; as this will format all
files.
Also, the project is documented with Doxygen, so remember of the documentation comments.
One very important design philosophy in SiNUCA3 is that everything should be explicit for the developer, but most things should be hidden from the user. This means that when developing the simulator, user-facing APIs should seek to give nice abstractions around the implementation, while the code developers use should seek to be clear and explicit about what it's actually doing.
Also, avoid writing "meta-components" or any other abstraction on top of the
component system. There's only one, direct way of writing a component: Creating
a class that inherit Component<T> and implementing it's clock algorithm there.
Abstractions in the name of code reuse will make everyone's life harder.
We mostly follow Google's C++ Style Guide with some extensions:
- As of code styling, we use the following
.clang-format:BasedOnStyle: Google IndentWidth: 4 AccessModifierOffset: -2 PointerAlignment: Left - We use
.cppfor C++ and.hppfor C++ headers. Similarly, the include guards ends withHPP_. - Static storage duration still should be avoided but we're more permissive towards it then Google due to the nature of our project.
- Usually you should only inherit from virtual classes.
- Operator overloading is strictly forbidden.
- We do not use references, only raw pointers. Of course we do not use smart pointers and move semantics as we're stuck in C++98.
- We do not have
cpplint.py. - Don't use friend classes.
- Use
cstdioinstead ofiostream. Actually, use the SINUCA3_*_PRINTF macros. - Use
NULLfor null-pointers as we're stuck in C++98. - Don't use type deduction.
- No boost library is aprooved.
- Variables, attributes and namespaces are
camelCaseand without any prefix or suffix. - Constants are
ALL_CAPS, just like macros (that of course should be avoided). - Enum names are
PascalCasejust like functions and types. - In the overall, avoid complicating stuff.
HiPES is an inclusive place. Remember that.