Menu

#127 QSPY Rejection Filter

QP-C-C++
closed
Qspy (3)
1
2024-04-02
2017-06-23
No

The usefulness of QSPY degrades quickly when there exists one or more AOs that have frequent state transitions. Say for example, a communications AO that is constantly transitioning between Idle and Waiting for an acknowledgement.

What is requested is a way to supress this noise unless needed as mentioned in the following: thread.

Currently I see 2 ways to implement this:

1) Change QSPY host application allow the supression of "unregistered" objects.
For example, an optional command line argument could tell QSPY to not display signals, objects, or states that have not had their dictionaries sent. Of course, this could be misleading, so the first time a "unmapped" value comes accross in this mode it should print something like "WARNING UNREGISTERED <sig,obj,fun> DETECTED". After that, unmapped values wouldn't show up. So using this flag, we would just not send the dictionary for things we didn't care about. This would affect the new feature of adding automated QSPY generation as part of QM.</sig,obj,fun>

2) Provide a rejection filter macro to QSPY.
This is a better solution performance-wise since the QSPY data wouldn't going across the wire in the first place. For example QS_REJ_FILTER_AO_OBJ, QS_REJ_FILTER_SIG, QS_REJ_FILTER_FUN. Of course this may be more difficult to implement since it's on the embedded code side.

Thanks,
:Dominic;

Discussion

  • Quantum Leaps

    Quantum Leaps - 2017-07-03

    Large part of the proposed "Rejection Filters" seem to be achievable with the existing "QS Local Filters". Have you considered using "Local Filters" in your case?

    --MMS

     
  • Quantum Leaps

    Quantum Leaps - 2017-07-14

    The proposed feature of a "Rejection Filter" works exactly the opposite way to the "Local Filters". So, in a sense one is the complement of the other.

    It should be clear that every such filter adds run-time (and code size) overhead to the tracing instrumentation, because all these filters must be checked at run time for each and every trace record produced. At some point the overhead might be so big that it would defeat the purpose of "non-intrusive" tracing.

    So the point is that by design a "Rejection Filter" would be in conflict with the existing "Local Filters", so it follows that your suggestion is to effectively reverse the "Local Filters" and make it into "Rejection Filters". This, of course, would have big impact on backwards-compatiblity. It's not sure at this time how to reasonably reconsile these concerns.

    And also, what if you have two or three such "spammy" AOs? Should a "Rejection Filter" reject an open-ended number of AOs?

    Any comments would be appreciated.

    --MMS

     

    Last edit: Quantum Leaps 2017-07-14
  • Dominic Valentino

    I understand your concern about overhead, that's why I implemented this feature by modifying our QSpy host application to not print out any state transitions that we want to ignore. It uses the function name as the key to this look up. Currently I have manually added these magic strings to the host application (blech).

    My first suggestion, where the absense of a function or object dictionary results in that item not being printed would take care of having to pass the spammy names to qspy host somehow.

    And also, what if you have two or three such "spammy" AOs? Should a "Rejection Filter" reject an open-ended number of AOs?

    Yes, this would probably be a need.

    If it is done on the host side, it is not a problem as all a user would have to due is not send object or function dictionaries for spammers to the host.

    In short, I belive option 1 will accomplish the same thing as an embedded rejection filter without having to modify QP itself. I can close this feature request and open a new one on the QSpy host application if you think it is worthwhile.

    I don't think it would be too hard to implement. Just have everywhere Dictionary_get is used for an object or state pointer check for a missing dictionary and skip the printf if the QSpy host is configured not show missing dictionary keys.

    For example:

    #define ERROR_MISSING_DICT -1 
    
    static char const *Dictionary_get(Dictionary * const me,
                                      KeyType key, char *buf)
    {
        int idx;
        if (key == 0) {
            return "NULL";
        }
        idx = Dictionary_find(me, key);
        if (idx >= 0) {
            return me->sto[idx].name;
        }
        else {                                                 /* key not found */
    
            if (l_show_missing_dictionary_keys) {
                if (buf == 0) {                       /* extra buffer not provided? */
                    buf = me->notFound.name;           /* use the internal location */
                }
                /* otherwise use the provided buffer... */
                if (me->keySize <= 4) {
                    snprintf(buf, NAME_LEN, "%08"PRIX64"", key);
                }
                else {
                    snprintf(buf, NAME_LEN, "%016"PRIX64"", key);
                }
                //Dictionary_put(me, key, buf);            /* put into the dictionary */
                return buf;
            }
            else {
                return ERROR_MISSING_DICT;
            }
        }
    }
    

    Thanks,
    Dominic

     
  • Dominic Valentino

    This problem has again bit us on my current QP project. I'm in a meeting trying to explain to the customer why we can't use Q_SPY to validate state changes between our AOs because our communications AO is overloading the buffer.

    In our case, using qspy also prevents the application from running correctly because of the overhead from the AO flooding the QSpy buffer which keeps interrupts disabled longer in QK_onIdle. So we will have to use QS_FILTER_SM_OBJ() on some AO but that's not very useful when we are trying to debug AO interactions.

    I am willing to pay for the overhead of another check for individual object filters that we can turn on and off. Maybe this extra level of filtering could be switched off with a preprocessor configuration?

     
  • Anonymous

    Anonymous - 2020-09-02

    This last update clearly indicates that any desired solution must be on the Target side, when the QS Target Component produces the data. Only this would reduce the overhead and would also reduce the amount of data produced.

    One option for designing such a "rejection filter" would be to use a design similar as in publish-subscribe. Specifically, the whole filter could be similar to QSubscrList. A priory-set, where each bit corresponds to the unique priority of an active object can capture the whole "rejection filter" (or "acceptance filter"). Something like this could be checked very efficiently...

    Of course, a filter like that would apply only to AOs, because only AOs have the priority. This is a non-trivial limitation, because state-transitions and other such QS trace records pertain also to state machines that are not necessarily active objects (e.g., state machines that are "orthogonal components")....

    Please let me know if something like that would be helpful in this case.

    --MMS

     
  • Dominic Valentino

    Miro,

    Thank you for considering this. One of the top selling features that I promote with QP is QSpy. In only but the most trivial of applications there will be some sort of communications happening and using an AO for fast stateful coms is a slam dunk.

    In regards to the implementation, I'm not sure I understand it. My (perhaps naive) approach, would be to modify the existing code with a reject clause, something like:

    #define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_) \
        if (QS_GLB_FILTER_(rec_) \
            && ((((objFilter_) == static_cast<void *>(0)) \
                || ((objFilter_) == (obj_)))
             &&  (IS_NOT_REJECTED(obj_)))
                )) \
        { \
            QP::QS::beginRec(static_cast<uint_fast8_t>(rec_));
    ...
    

    My parans are wrong above, but I think you get the idea.

    How the macro IS_NOT_REJECTED would work could be done multiple ways. If the reject feature is not enabled, it could just be defined as true and it wouldn't affect performance at all.

    Otherwise it could traverse a list of rejected objects which get added with something like:

        QS_ADD_REJECT_FILTER_SM_OBJ(obj);
        QS_ADD_REJECT_FILTER_AO_OBJ(obj);
    

    These could add the filter to QP::QS::priv.locFilter or someplace entirely different.

    Now, it's very expensive to loop and check these, so the IS_NOT_REJECTED macro could loop unroll to some limited number of filters. For example, let's say you only allowed 3 reject filters:

    #define IS_NOT_REJECTED(obj_) \
    !((obj_ == filter[0])  || (obj_ == filter[1])  ||  (obj_ == filter[2]))
    

    I'm sure I'm waving my hands and some critical detail or potential problem with this approach like its interaction with Qutest or something.

     

    Last edit: Dominic Valentino 2020-09-03
  • Quantum Leaps

    Quantum Leaps - 2020-09-11

    Hi Dominic,
    I'd like to give you a quick update that the QS "local filter" is being redesigned to support your requested featrue. Specifically, the QS "local filter" will allow you to filter simultaneously up to 127 objects, including all active objects (upto 64 of them).

    The implementation will be based on the "object-id", which will be a number in the range 1..127 associated with the object. The "object-ids" for AOs will be their unique QP priorities, so the application developers don't need to worry about these. There will be also upto 15 object-ids reserved for the event-pools and memory-pools and additional 15 for free event-queues. Finally, there will be 32 object-ids available for "application-specific" objects. These should give you plenty to filter on/off.

    The nice thing about this implementation is that the overhead of the re-designed local filter will be small, about the same as the previous address-based local filter.

    The change should be done and released still in September, 2020.

    --MMS

     

    Last edit: Quantum Leaps 2020-09-11
  • Dominic Valentino

    Miro,

    Thank you!
    Thank you!
    Thank you!
    Thank you!
    Thank you!
    Thank you!
    Thank you!

    But, I hope this isn't a breaking API change that will cause the community to come after me with pitchforks!

    We will be letting the customer know the good news today.

    -Dominic

     
  • Quantum Leaps

    Quantum Leaps - 2021-01-15
    • status: pending --> closed
     
  • Quantum Leaps

    Quantum Leaps - 2021-01-15

    Implemented in QP/C/C++ 6.9.1.
    --MMS

     
  • Anonymous

    Anonymous - 2024-04-02
    Post awaiting moderation.

Anonymous
Anonymous

Add attachments
Cancel





MongoDB Logo MongoDB