njc
njc

Reputation: 77

conditional logging in dml for speed in production environments

I would like to optimize the dml-code I have for speed in a production environment. As far as I understand log statements such as:

log info, <n>: <string>;

Get translated in at least one if statement in the executable, because there is a need to check whether the log-level is larger than n.

I would like to avoid that by throwing the if statement out of the executable similar to #define and #ifdef statements in C and the only way I found in dml is by defining a constant and checking it and hoping the compiler will optimize out the code, recognizing it will never be executed.

constant LOG = 1; // there is not even the possibility to define a bool constant

if (LOG) log info, <n>: <string>;

My questions are:

Thanks in advance.

Upvotes: 1

Views: 68

Answers (3)

Erik Carstensen
Erik Carstensen

Reputation: 898

My first reaction is that you should reconsider your ambition to do optimizations on this level. Do you have benchmarks that prove this code to be a bottleneck? The devices of a system seldom account for more than 5-10% of the total simulation time, and account for a vast majority of the development effort, so your device development effort is better spent on maintainability. There are definitely cases where devices account for more than that; in this case you need to understand why. It's often caused by a busy-wait loop, and there are techniques like hypersimulation that can be used to fast-forward simulation over busy-wait loops.

Also, the if generated by a log statement is an easy-to-predict branch instruction, so you will have a hard time even measuring the speed of it.

However, you may have other valid reasons for making sure a debug log is left out from the binary, e.g. concerns about code size or confidentiality. If you want to ensure that a statement stays outside the compiled result, then use #if instead of if. This ensures the body is expanded in compile-time; the discarded branch is even allowed to reference nonexistent identifiers.

To summarize, my answers to your three questions are:

  • #if may be a better choice
  • #if gives you a hard guarantee that the code will be optimized out by DMLC; if you use if then it will certainly be eliminated by the C compiler if you compile with optimization flags, but there is no formal guarantee.
  • You can read the DML-generated code, <host>/obj/modules/MODULE-NAME/DEVNAME-dml.c.

And a final note: The recommended construct for constants in DML 1.4 is param; you can write param LOG = true;. constant is a remnant of DML 1.2, which remains only to bridge a current compiler limitation (params cannot be used when specifying array sizes in typedefs).

Upvotes: 1

Love Waern
Love Waern

Reputation: 188

Note that trying to optimize away log statements (beyond the use of log levels/groups) is very likely premature, and only adds unneeded complexity to the model if so -- modeled devices only very rarely present a bottleneck within a simulation. Verify that the log statements actually do have a significant impact before resorting to trying to optimize them away.

That said, to answer each question in turn:

1. Use the compile-time if (else) statement (which is also available as an object statement):

param do_log = true;
method m() {
    ....
    #if (do_log) log info, <n>: <string>;
}

Also note the use of param instead of constant here. param is superior to constant in every way, with the only exception being that they can't be used within typedefs. As a plus, parameter definitions can even be made through the DMLC flag -D, which is useful for this kind of conditional compilation.

2. The DML compiler typically doesn't eliminate any operations which aren't explicitly compile-time (like #if is). This is true for the run-time if statement: it won't get eliminated by DMLC no matter how simple the condition is. However, as DMLC generates references to constant/param by simply replacing them by their definitions, the C compiler will receive a if (1) or if (0) and so will almost certainly optimize the branch away.

3. As DMLC generates C, and generates that C with line directives to the original source file (unless --noline is provided to DMLC), you can look up the generated C corresponding to a given DML statement by searching for #line [line of statement in DML source file] [path to DML source file]. Although the generated C is certainly hard to read, for some simple statements like if the generated code can almost get verbatim to the original DML.

Upvotes: 3

jakobengblom2
jakobengblom2

Reputation: 5888

To expand on the other answer: you can use #if and a param. Like this:

// Not a complete device model
dml 1.4; 

param log_reg_bb_r50 = false;

// some bank
bank bb {

    register r50 size 8 @ 0x50 is write {
        method write(uint64 v) {
            default(v);
            log info, 1 : "Write to R50, standard log";
            #if(log_reg_bb_r50) {
                log info, 1 : "Write to R50, conditional log";
            }
        }
    }
}

Upvotes: 0

Related Questions