Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support dumping dependency tree in dot format #20

Open
YarikTH opened this issue Mar 20, 2021 · 4 comments
Open

Support dumping dependency tree in dot format #20

YarikTH opened this issue Mar 20, 2021 · 4 comments

Comments

@YarikTH
Copy link
Owner

YarikTH commented Mar 20, 2021

Context should have some methods to dump debug info into the specified stream.
Possible info that can be dumped:

  1. type of the signal value (need some code to support stringify names of the types)
  2. value of the signal
  3. name of the react node (need to optionally pass on node creation)
  4. group of the signal? For e.g. all signals of one object can be grouped under some id
@YarikTH
Copy link
Owner Author

YarikTH commented Jun 12, 2022

Better idea: introduce node visiting feature. Pass visitor like functor to receive full info about used nodes. Like

struct F
{
  void operator()( node_info::id );
  void operator()( node_info::depth );
  void operator()( node_info::label );
  void operator()( node_info::children );
  void operator()( node_info::value<T> );
  void operator()( node_info::type<T> );
  // maybe node_type? signal/event/observer
};

context ctx;
ctx.peek_node_info( F() );

So user can use such info for whatever reason and convert it into needed format.

To achieve this context should have pointers to at least 0 depth nodes so we can iterate them. Also we need interface to add custom labels to nodes. This feature should be disableable using define, because it adds runtime overhead to store node pointers in context and to store label strings in nodes.

@YarikTH
Copy link
Owner Author

YarikTH commented Jun 12, 2022

Maybe reimplementing of logging interface is fine too.

@YarikTH
Copy link
Owner Author

YarikTH commented Oct 28, 2023

I think that it is easier to make it all via IListener interface that can be passed on the context creation. This interface will be analog of cpp.react's EventLog and IReactiveEngine. If user receive events about all the internal actions, then he can not only regenerate node graph on his side, but also see all the process, visualize it in any way he wants.

Here is combination of cpp.react's interfaces with descriptions:

struct IReactiveEngine
{
    // Hard to understand that it means exactly.
    // It is range between turn creation and actual change propagation
    void OnTurnAdmissionStart(Turn& turn)  {}
        // No event
    void OnTurnAdmissionEnd(Turn& turn)    {}
        // No event

    // Change propagation
    void Propagate(Turn& turn)  {}
        // No event

    // Node creation/destruction
    void OnNodeCreate(NodeT& node)  {}
        class NodeCreateEvent
    void OnNodeDestroy(NodeT& node) {}
        class NodeDestroyEvent

    // Static attach/detach on creation/destruction
    void OnNodeAttach(NodeT& node, NodeT& parent)   {}
        class NodeAttachEvent
    void OnNodeDetach(NodeT& node, NodeT& parent)   {}
        class NodeDetachEvent

    // Dynamic attach/detach in the process of change propagation. Needs extra actions, but basically the same
    void OnDynamicNodeAttach(NodeT& node, NodeT& parent, Turn& turn)    {}
        class DynamicNodeAttachEvent
    void OnDynamicNodeDetach(NodeT& node, NodeT& parent, Turn& turn)    {}
        class DynamicNodeDetachEvent

    // Pulse means that IReactiveNode::Tick() did something, so children should be updated.
    // IdlePulse means that IReactiveNode::Tick() did nothing
    void OnNodePulse(NodeT& node, Turn& turn)      {}
        class NodePulseEvent
    void OnNodeIdlePulse(NodeT& node, Turn& turn)  {}
        class NodeIdlePulseEvent

    // Called inside IInputNode::ApplyInput(void* turnPtr) to notify that input node is triggered
    // Basically the same as OnNodePulse, but for input nodes
    void OnInputChange(NodeT& node, Turn& turn)    {}
        class InputNodeAdmissionEvent

    // Events inside IReactiveNode::Tick(void* turn) that show where actual calculation is performed
        class NodeEvaluateBeginEvent
        class NodeEvaluateEndEvent

    // Not used in legacy1 cpp.react
        class TransactionBeginEvent
        class TransactionEndEvent
        class UserBreakpointEvent
};

Ureact has derived from cpp.react and evolved a little, so interface would differ. So, it is better to start from the easiest cases like nodes construction/destruction and their connections and continue form this.

Such logging facility is not free performance wise, so it should be optional and lay under some define that can disable it when it is not needed.

Unlike EventLog that has timestamps and tons of separate event classes with own serialization, I see ureact log interface as a IReactiveEngine's analog with tons of virtual methods which user should overload to be notified. So user can get the timestamp, and other info he likes.

Also, seeing tree of anonimous nodes which types, values etc we can't see it is not so informative, so need to come up with some idea how to add such info and pass it in the interface.

@YarikTH
Copy link
Owner Author

YarikTH commented Oct 28, 2023

Also, it's good idea to make #125 first. Because otherwise logging interface will be in details namespace, because it uses classes and enumerations from this namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant