About GBL Designer |
|
![]() |
|
| GBL Designer is a graphical environment intended to simplify creating event-drivent designs which use GBL Simulation Library . GBL Designer uses schematic approach to designing and testing of GBL modules. This approach frees a developer from the need to remember the details of GBL Simulation Library , generating the C++ library code and building binaries automatically, thus eliminating errors, saving time, and allowing a developer to focus on more creative work. Since GBL designer decouples schematic representation from the library implementation, it allows easier evolution of library code without breaking backward compatibility. GBL Designer also helps with design modifications, providing automatic changes that keep different parts of the design and imported modules in sync, making the necessary changes to the generated C++ code. All that turns a tedious error-prone work of direct coding for the simulation library into an enjoyable experience working in GBL Designer. | |
Starting a new project |
|
![]() |
|
| GBL Designer on start creates a new empty project and names it project1 . You can create a new project at any time by pressing the New button or selecting File/Start New Project command from the menu. | |
![]() |
|
|
When a new project is created, the Project Manager shows a design tree with only one subnode called project1 . You can change name, location, and other project properties by selecting the project node and modifying values in Properties Window . |
|
Project Manager |
|
![]() |
|
|
Project Manager
presents a hierarchical view of the design. It shows expandable tree nodes, corresponding to the modules, ports, wires, functions, instances, texts. Project Manager
is synchronized with the Property Manger
to allow editing properties of the selected node. It is also synchronized with Module View
, so selecting an element in the Module View automatically selects the same element in the Project Manager
tree.
There are five buttons on the Project Manager caption bar:
|
|
Properties Window |
|
![]() |
|
|
Properties Window
shows a list of properties of the selected node in the Project Manager
. Some properties are read-only, other can be modified.
GBL Designer Properties :
Project Properties:
Module Properties:
Port Properties:
Wire Properties:
Function Properties:
Text Properties:
Instance Properties:
|
|
Module View |
|
![]() |
|
| Module View window displays the graphical view of the module. On the top bar, it contains buttons that allow adding basic elements to the module: ports, connections, functions, text, module instances . Select the element and click anywhere in the window to place it. By holding Ctrl key, you can add multiple instances of the selected element. Entering connections follows somewhat different procedure. Because it's likely a connection would have more than two points, each mouse click adds a connection vertex allowing to continue defining that connection. By holding down a Ctrl key when clicking left mouse button, a connection will be closed. Alternatevely by clicking on the right mouse button, unfinished segment is deleted and connection is closed. Pressing ESC key during any operation cancells it. Click and drag left mouse button to select the elements. If you hold down Ctrl button, the new selection is added to the existing one. Otherwise the existing selection is de-selected. Selection can be moved, deleted, or duplicated. To move selection, click and drag it with the left mouse button. To delete or duplicate selection use the corresponding buttons on the toolbar. The Properties Window always displays the first element of the selection. You can change the design size of the module canvas by changing Page Height and Page Width properties of the corresponding module. | |
Code Generation |
|
![]() |
|
Open Header
and Source
tabs to see code that GBL Designer
generated for the current design. You can modify code inside the GBL User Code region:#pragma region GBL User Code #pragma endregion This region will not be modified by the Designer. Any changes outside this portion of code will be discarded by the Designer. Inline Functions property (see Module Porperties ) determines whether the code for event handlers , fibers , and threads goes to the header file or to the source file. Since most compilers at this time do not support exported templates, you will need to specify Inline Functions = yes for template modules. If you decide to explicitly specialize template modules you can select either inline or outline definitions. |
|
Building Project |
|
![]() |
|
|
Click Open Modules in IDE Build Targets Run Test Modules will run the test modules that were successfully compiled. | |
GBL Simulation Library | |
| GBL Simulation Library provides a number of classes to simplify event-driven designs. It provides virtual and real-time schedulers, events, signals, ports, fibers, threads, modules and other classes implementing all essential parts of such designs. All facilities in GBL Simulation Library are declared in GBL namespace. The GBL Simulation Library is automatically linked to the designs created in GBL Designer. If you create designs manually, you need to include gbl.h header file and link to the approprate version of gbl.lib. When building using dynamically linked library gbl.dll must be available during run time. | |
GBL Time Models |
|
There two time classes provided in sim_time.h file. One is generic class template: template<class T> class TimeT;And the other is real-time class: class RealTime : public TimeT<double>The time span is described by nested class Diff.
Header file defaults.h defines default simulator virtual time typedef:
typedef TimeT<unsigned> SimTime;and virtual and real-time constants: const SimTime::Diff Tick(1); const RealTime::Diff Day(1.); const RealTime::Diff Hour(1/24.); const RealTime::Diff Min(1/24./60.); const RealTime::Diff Sec(1/24./60./60.); const RealTime::Diff Msec(1/24./60./60./1000.);If you change the default time classes used by GBL simulator, you will need to recompile the simulation library and the projects it is linked to. |
|
GBL Data Types |
|
GBL Simulation library provides additional data types for system modeling.
enum LogicValue { logic_0 = 0, logic_1, logic_x, logic_z };
class Bit;
class Logic;
template<size_t N> class BitSet;
template<size_t N> class LogicSet;
Types Bit and Logic represent 2-bit (logic_0, logic_1) and 4-bit (logic_0, logic_1, logic_x, logic_z) logic. These types have constructors and assignment operators from char and bool.
Templates BitSet<N> and LogicSet<N> represent arbitrary sized vectors of Bit and Logic values. They have constructors and assignment operators from integral types
, from std::string and const char*, and from other bit types. Operators and functions that define interface for these types are listed below:
|
|
GBL Globals |
|
Global functions in GBL namespace: Simulator& GetSimulator()-- function returns reference to the default simulator. SimTime Module::GetSimTime();-- function returns current simulation time. RealTime Module::GetRealTime()-- function returns current real time. Event& eReset() -- a reset event happens after calling Event& eStop() -- a stop event happens after calling Event& eIdle()-- an idle event, which occures when the event queues are empty. Event& eTick()-- a tick event, which happens when the virtual time advances. Event& eRtTick()-- a real time tick event, which happens when the real time advances. void Reset()-- cleans the event queues and issue reset event.Fibers and Threads are not affected. void Run(SimTime::Diff t, RealTime::Diff tr)-- run simulator until specified simulation or real time elapses. void Run(SimTime::Diff t)-- runs simulator t ticks only. Real-time scheduler is not run.
void* RunAsync() -- starts simulator run in a separate thread and exits immediately. Simulator can be stopped by calling Simulator::Stop() function. Returned value is Windows thread handle. It can be used in Windows API accepting thread handles. For example, you can use void Close()-- function terminates all GBL Threads. Since threads cannot becontrolled by the simulator, they may continue to modify event queues after the simulator object has been already destroyed causing unhandled exceptions on program exit. Calling Close() before the termination of the program terminates all threads while the simulator is still alive. This function call is only necessary if the application creates GBL threads.
Global functions in defaults.h: std::ostream& Log()-- returns ostream object that logs simulator messages. void SetLog(std::ostream&)-- directs simulator messages to the specified ostream. void SetLog(const std::string& file_name)-- directs simulator messages to the specified file. void LogException()-- default exception dispatcher, can be used in custom OnException() function. |
|
GBL Modules |
|
|
GBL Module class is the base class for all user-defined modules. class Module : public EventHandler
{
public:
// module constructor accepts a string argument as instance name
Module(const std::string& name = "");
// GetName returns module instance name
const std::string& GetName() const;
// MakeThread creates preemptive thread out of member function
template<class M>
void MakeThread(void (M::*f)());
// MakeFiber creates a non-preemptive fiber out of member function
template<class M>
void MakeFiber(void (M::*f)());
// Enqueue schedules function to be executed in a thread pool
// function is guaranteed to be executed in the current delta cycle
// execution of enqueued functions is neither ordered nor sequenced
template<class M>
void Enqueue(void (M::*f)());
protected:
virtual void OnException() const;
};
Override OnException() to provide specific exception handling in user-defined modules.
class Example1 : public GBL::Module
{
public:
Example1() : GBL::Module("example1")
{
MakeThread(&Example1::Print);
}
private:
void Print()
{
GBL::Wait(GBL::Sec);
std::cout << "Print() called ...\n";
}
};
GBL Module class inherits from EventHandler
class, which provides facilities for event scheduling.
In order to make an event handler out of member function use Handler() or AsyncHandler() functions. |
|
GBL Events |
|
Event classes contain ActionFunction objects, which are wrapped pointers to the event handlers.
class EventHandler;
typedef void (EventHandler::*Action)();
class ActionFunction;
Events provide facilities for binding and executing of the event handlers, according to the event type.
Event classes in GBL are derived from class EventBase, which specifies the following virtual interface: void Bind(const ActionFunction&)-- binding of event handlers. Event handlers are bound permanently, unless Unbind()function removes binding. void BindTemp(const ActionFunction&) -- binding of temporary event handlers. Temporary binding is removed after event is raised. void BindAsync(const ActionFunction&) -- binding of asynchrous event handlers. void Execute()-- executing of the bound event handlers. size_t ActionCount() const-- number of event handlers event object holds. size_t TempCount() const -- number of temporary event handlers event object holds. size_t AsyncCount() const -- number of asynchronous event handlers event object holds. ActionFunction Unbind()-- unbind and return the last bound event handler. ActionFunction UnbindTemp() -- unbind and return the last bound temporary event handler. ActionFunction UnbindAsync() -- unbind and return the last bound asynchronous event handler. The following event classes are defined in GBL:
|
|
GBL Signals |
|
Signals just like events allow binding of the event handlers.
Additionally they hold an object of specified type by value. For example,
Signal<int> holds an int variable, Signal<vector<int>> holds a vector.
Since signals implement value semantics, one must pay attention to avoid costly
copying of the large objects.Signals execute bound event handlers when the value of the variable that signal holds changes, or when an optional Condition is satisfied, i.e.
Condition()(new_value, old_value) evaluates to true.Initial value for the signals can be specified in their constructors. If no initial value specified the default initialization takes place. Signals provide conversion operator T ()
to the signal data type, as well as Read() function for cases when implicit conversion cannot be performed.Assignment operator for writable signals is resolved to Write() function. Writable delayed signals accept
optional time parameter for delayed writing, as well as operator ()(TimeT delay), e.g. the expressions
(1) and (2) below perform the same delayed writing to the signal, while expressions (3) and (4)
perform zero-delayed writing: GBL::Signal<bool> signal; signal.Write(true, 5 * GBL::Tick); // (1) signal(5 * GBL::Tick) = true; // (2) signal.Write(true); // (3) signal = true; // (4) Signal TypesThe signal types defined in GBL are listed below.template<class D> class ConstSignal;-- constant signal, it never changes its value after initialization and therefore never raises events. Signal data type is D.
template<class D, class E = Event> class ReadSignal;-- a signal, which can be read, but cannot be written. In addition to data type D you can specify
event type E
template<class D, class E = Event, class Condition = EventHandler::NotEqual> class DirectSignal;-- DirectSignal is never scheduled, it triggers event handlers bound to it immediately.
In addition to data and event types, you can specify a condition type, which
triggers event handlers bound to the signal.
template<class D, class E = Event, class Condition = EventHandler::NotEqual> class Signal;-- a general signal type, which can be read and written. It schedules bound handlers with a delay (zero-delay by default.) Signal Condition
DirectSignal and Signal types accept optional Condition type,
which allows to
specify the trigger condition. Event handlers are invoked when
Condition(new_value, old_value) evaluates to true. Default condition type is
EventHandler::NotEqual, which means that every time a new value is not equal to
the old value, the event handlers are invoked.
GBL library provides several predifined common conditions: Always<true> and Always<false> -- always evaluate to true and false
correspondingly;PosEdge and NegEdge -- trigger event handlers on positive and negative edge
correspondingly using operator< on signal data type;Equal and NotEqual -- trigger event handlers using operators == and !=
correspondingly.PosEdgePtr, NegEdgePtr, EqualPtr, NotEqualPtr -- same as above, but dereference signal values to
work on data types which are iterators (pointers).Using subscriptsData types that implement subscript operator can be efficiently accessed through signal'soperator[]. Signal class returns proxies which provide access to the
data by index and perform delayed writing.Execute FunctionsSignal behave like value types.Read() function returns a const reference to the object
and Write() functions assign a
new object.
So, for example, to modify an object by calling its member function would
involve reading to a temporary object, modifying and writing it to a signal.
This can be problematic when a copy expensive object is hold by a signal. In
order to avoid expensive copying, Signal class provides Execute functions, which accept a functional
object and performed its delayed execution:
A function object must define bool operator(D&), which will be called by
the scheduler. Return value of operator(D&) defines
whether the execution of this function object should trigger bound event
handlers or not. In C++0x it can be a lambda function. For example, using VC++ 2010, we can
create a module that counts characters in every word in input text and keeps a map
in its output port:
| |
GBL Ports |
|
Port classes implement generalized signal pointer types and provide means for delayed bindings of the signals.
They provide the same Read, Write, and Execute facilities as the underlying
signals. From a design point of view, ports represent public module interface, through which the signal flow occurs. Thus ports efficiently decouple module design from its environment.
The following port types are defined in GBL:
class UnconnectedPort;-- represents unconnect port. For unconnected ports constants template<class S> class Port;-- a general type port, that can be bound to any signal type template<class D> class InPort;-- input port (can be read, but not written) accepting signal with data type Ports can be bound to other ports or signals. GBL defines macrostemplate<class D, class E = Event, class C = EventHandler::NotEqual> class OutPort;-- output port, accepting Signal<D,E,C>. GBL_CONNECTORN(p1, p2, ... , pN) for port binding in the module. For example, an inverter
with one input and one output port would have GBL_CONNECTOR2(in, out) statement. To connect external signals to an inverter
instance, they must be listed in the same order (positional binding) using operator ()(), e.g.
GBL::Signal<bool> sig_in; GBL::Signal<bool> sig_out; inverter inv; inv(sig_in, sig_out); Alternatively, if ports are made public (not recommended), a binding can be done by name (nominal binding): GBL::Signal<bool> sig_in; GBL::Signal<bool> sig_out; inverter inv; inv.in(sig_in); inv.out(sig_out); |
|
GBL Event Handlers |
|
Event handlers are member functions of modules derived from Module
(or EventHandler
) class, that have the following signatures: void (user_defined_module_class::*)();
void (user_defined_module_class::*)()const;
You can also use lambda functions and binders in event handlers if target
comiler supports these C++0x features (VC++ 2010).
Use Handler() function to form an event handler. To bind an event handler to the events, signals, or ports use operator << (). For example, the following code creates event handler from OnSomeEvent() function and binds it to some_event event.class MyModule : public GBL::Module
{
void OnSomeEvent() { /* do synchronous processing */ }
void OnSomeEventAsync() { /* do asynchronous processing */ }
void OnOtherEvent() { Enqueue(&MyModule::OnOtherEventAsync); }
void OnOtherEventAsync() { /* async executed */ }
GBL::Event some_event;
GBL::Event other_event;
GBL::Signal<bool> some_signal;
public:
MyModule()
{
// create a handler from OnSomeEvent and make it sensitive to some_event event
Handler(&MyModule::OnSomeEvent) << some_event;
// create an asynchronous handler from OnSomeEvent and make it sensitive to some_event event
AsyncHandler(&MyModule::OnSomeEventAsync) << some_event;
// create a handler from OnOtherEvent and make it sensitive to other_event event
Handler(&MyModule::OnOtherEvent) << other_event;
// create a handler from lambda function (C++0x)
Handler([this](){ cout << "\nsome_signal changed at " << GetSimTime(); }) << some_signal;
}
};
When The last line demonstrates the use of lambda function as a handler for Function execution in the current delta cycle is neither ordered nor sequenced.
|
|
GBL Fibers and Threads |
|
|
GBL provides two classes for building asynchronous designs: Unlike asynchronous event handlers, which are executed in thread pool, Thread
function creates an physical thread and runs in infinite loop. So the number of Thread
objects that can be created is significantly smaller than the number of asynchronous event handlers. You can also use Module
class provide two functions, Example: class MyModule: public GBL::Module
{
GBL::InPort<bool> in;
void fiber() { Wait(in); std::cout << "\nInput changed: " << in; }
void thread(){ Wait(GBL::Hour); std::cout << "\nOne hour elapsed"; }
public:
MyModule()
{
MakeFiber(&MyModule::fiber);
MakeThread(&MyModule::thread);
// using lambda function to print simulation time every second
MakeThread([this](){ Wait(GBL::Sec); std::cout << "\nSimTime: " << GetSimTime(); });
}
}
Since fibers and threads always run in an infinite loop, they must have template<class E> void Wait(E& e)-- waiting on event/signal/port template<class S, class BinaryPredicate> void Wait(S& s, typename RefTraits<typename S::DataType>::cref value, BinaryPredicate p)-- waiting on signal/port until p(s, value) turns to truetemplate<class S> void Wait(S& s, typename RefTraits<typename S::DataType>::cref value)-- waiting until signal/port value becomes equal to value
void Wait()-- waiting until the current cycle of zero-queue void Wait(SimTime::Diff t)-- waiting for t simulator ticks void Wait(RealTime::Diff t) -- waiting in real time Threads might also need to lock shared data to prevent collisions. GBL provides the following classes (in lock.h ) to lock shared resources:
Mutex m;
{
Lock l(m);
locked_scope;
}
Mutex m;
Lock l(m);
locked_scope;
{
Unlock u(l);
unlocked_scope;
}
locked_scope_continued;
|
|
Examples |
|
|
Examples shown in this section are created for demonstration purposes only. Download project file: examples.gbl Download invertor module file: inverter.gblmod Download And2 module file: and2.gblmod Download Selector2 module file: selector2.gblmod Download Handshake module file: handshake.gblmod Download test module file: test.gblmod |
|
Inverter |
|
![]() |
|
|
Inverter module performs boolean function
In GBL Designer create one GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: inverter
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef inverter_H9727
#define inverter_H9727
#include "gbl.h"
namespace examples {
class inverter : public GBL::Module
{
GBL::InPort< bool > in;
GBL::OutPort< bool > out;
public:
GBL_CONNECTOR2(in, out)
inverter(const std::string& name = "") : GBL::Module(name)
{
Handler(&inverter::OnInput) << GBL::eReset() << in;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnInput()
{
out = !in;
}
#pragma endregion
};
} // namespace examples
#endif
|
|
And2 |
|
![]() |
|
|
And2 module performs boolean function
In GBL Designer create two Select GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: And2
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef And2_H9728
#define And2_H9728
#include "gbl.h"
namespace examples {
class And2 : public GBL::Module
{
GBL::InPort< bool > in1;
GBL::InPort< bool > in2;
GBL::OutPort< bool > out;
public:
GBL_CONNECTOR3(in1, in2, out)
And2(const std::string& name = "") : GBL::Module(name)
{
Handler(&And2::OnInput) << GBL::eReset() << in1 << in2;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnInput()
{
out.Write(in1 && in2, GBL::Tick * 2);
}
#pragma endregion
};
} // namespace examples
#endif
|
|
Selector2 |
|
![]() |
|
|
Selector2 module performs selection operation:
In GBL Designer create two Add event handler Select GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: Selector2
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef Selector2_H9728
#define Selector2_H9728
#include "gbl.h"
namespace examples {
export template< class T >
class Selector2 : public GBL::Module
{
GBL::InPort< T > in1;
GBL::InPort< T > in2;
GBL::InPort< bool > select;
GBL::OutPort< T > out;
public:
GBL_CONNECTOR4(in1, in2, select, out)
Selector2(const std::string& name = "") : GBL::Module(name)
{
Handler(&Selector2::OnSelect) << GBL::eReset() << select;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnSelect()
{
out = select ? in1 : in2;
}
#pragma endregion
};
} // namespace examples
#endif
|
|
Handshake |
|
![]() |
|
|
GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: HandShake
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef HandShake_H9727
#define HandShake_H9727
#include "gbl.h"
#include <stdlib.h>
namespace examples {
class HandShake : public GBL::Module
{
GBL::OutPort< int > data;
GBL::Signal< bool > w_en;
GBL::Signal< bool > r_en;
public:
GBL_CONNECTOR1(data)
HandShake(const std::string& name = "") : GBL::Module(name)
{
Handler(&HandShake::OnReset) << GBL::eReset();
MakeFiber(&HandShake::writer);
MakeFiber(&HandShake::reader);
}
//<GBL_user>
private:
//----------------------------------------
void writer()
{
if(!w_en)
GBL::Wait(w_en, true);
int r = rand();
data = r;
std::cout << "\nwriter: " << r;
w_en = false;
r_en.Write(true, GBL::Tick);
}
//----------------------------------------
void reader()
{
if(!r_en)
GBL::Wait(r_en, true);
std::cout << "\nreader: " << data.Read();
r_en = false;
w_en.Write(true, GBL::Tick);
}
//----------------------------------------
void OnReset()
{
w_en = true;
}
//</GBL_user>
};
} // namespace examples
#endif
|
|
Test |
|
![]() |
|
|
GBL Designer generated code is shown below.
|
|
test.h file
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: test
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef test_H9727
#define test_H9727
#include "gbl.h"
#include "examples.h"
#include "BasicModules.h"
namespace examples {
class test : public GBL::Module
{
BasicModules::ClockGen i1;
inverter i2;
And2 i3;
Selector2< int > i4;
HandShake i5;
And2 i6;
GBL::Signal< bool > clk;
GBL::Signal< bool > inv_out;
GBL::Signal< bool > w1;
GBL::Signal< bool > clk_;
GBL::Signal< int > selector_out;
GBL::ConstSignal< unsigned > period;
GBL::Signal< bool > enable;
GBL::ConstSignal< int > const_10;
GBL::ConstSignal< int > const_1;
GBL::Signal< bool > and2_out;
GBL::Signal< int > hs_out;
void trace() { GBL::AddTrace(GetName() + ".and2_out", and2_out);
GBL::AddTrace(GetName() + ".clk", clk);
GBL::AddTrace(GetName() + ".clk_", clk_);
GBL::AddTrace(GetName() + ".hs_out", hs_out);
GBL::AddTrace(GetName() + ".inv_out", inv_out);
GBL::AddTrace(GetName() + ".selector_out", selector_out);
GBL::AddTrace(GetName() + ".w1", w1); }
public:
test(const std::string& name = "") : GBL::Module(name)
, i1(name + ".i1"), i2(name + ".i2"), i3(name + ".i3"), i4(name + ".i4")
, i5(name + ".i5"), i6(name + ".i6")
, period(10), const_10(10), const_1(1)
{
i1 ( period, enable, clk, clk_ );
i2 ( clk, inv_out );
i3 ( w1, clk, and2_out );
i4 ( const_10, const_1, clk_, selector_out );
i5 ( hs_out );
i6 ( inv_out, inv_out, w1 );
Handler(&test::OnReset) << GBL::eReset();
Handler(&test::trace) << and2_out << clk << clk_
<< hs_out << inv_out << selector_out << w1;
}
//<GBL_user>
private:
//----------------------------------------
void OnReset()
{
enable = true;
}
//----------------------------------------
void Run()
{
GBL::Run(GBL::Tick * 1000, GBL::Sec * 10);
}
//</GBL_user>
};
} // namespace examples
#endif
|
|
test.cpp file
//--------------------------------------------------------------------------------
// GBL Designer generated module implementation
// Module: test
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#include "test.h"
using namespace examples;
//----------------------------------------main
int main(int argc, char* argv[])
{
GBL::SetTraceFile("C:\\GBL\\Examples\\examples.trace");
examples::test("test").Run();
GBL::Close();
}
//<GBL_user>
//</GBL_user>
|
|
| After building and running test.exe , click on Tracer icon to open saved traces from this example. They should look like in the picture below. | |
![]() |
|