0

I have written the following piece in order to test a function, which implements a logarithmic hysteretic quantizer.

#include <iostream>
#include <Eigen/Dense>
#include <math.h>

double logarithmic_hysteretic_quantizer(double u, double u_prev, double delta, double u_min);

int main(int argc, const char * argv[]) {

    Eigen::MatrixXd control_signal = Eigen::MatrixXd::Zero(7,1);
    double delta = 0.1765;
    double u_min = 0.01;

    double i = 0.0;

    while (i >= -20.0) {
    
        std::cout << "FOR LOOP" << std::endl;
    
        control_signal << logarithmic_hysteretic_quantizer(i, control_signal(0,0), delta, u_min),
                          logarithmic_hysteretic_quantizer(i, control_signal(1,0), delta, u_min),
                          logarithmic_hysteretic_quantizer(i, control_signal(2,0), delta, u_min),
                          logarithmic_hysteretic_quantizer(i, control_signal(3,0), delta, u_min),
                          logarithmic_hysteretic_quantizer(i, control_signal(4,0), delta, u_min),
                          logarithmic_hysteretic_quantizer(i, control_signal(5,0), delta, u_min), 
                          logarithmic_hysteretic_quantizer(i, control_signal(6,0), delta, u_min);
    
        std::cout << control_signal << std::endl;
        std::cout << std::endl;
    
        i = i - 0.001;
    
        }
   return 0;
}

double logarithmic_hysteretic_quantizer(double u, double u_prev, double delta, double u_min) 
{

    double u_i = 0.0;
    double u_i_next = 0.0;
    double p = (1.0-delta)/(1.0+delta);

    /* For Debugging Purposes */
    std::cout << "INSIDE" << std::endl;
    std::cout << "U is: " << u << std::endl;
    std::cout << "U_PREV is: " << u_prev << std::endl;

    if (u < 0.0) {
        return -logarithmic_hysteretic_quantizer(-u, u_prev, delta, u_min);
    } else if (((u >= 0.0) && (u <= u_min/(1.0+delta))) || ((u < u_min) && (u > u_min/(1.0+delta)))) {
        std::cout << "DEAD ZONE" << std::endl;
        double w = 0.0;
        return w;
    
    } else {
    
        int i = 1;
    
        while(1) {
        
            u_i = pow(p,(1-i))*u_min;
            u_i_next = pow(p,(1-(i+1)))*u_min;
        
            if ( ((u > u_i/(1.0+delta)) && (u <= u_i) && (u_prev >= u_i)) || ((u < u_i/(1.0-delta)) && (u_i <= u) && (u_prev <= u_i)) ) {
            
                return u_i;
            
            } else if ( ((u_i < u) && (u <= u_i/(1.0-delta)) && (u_prev >= u_i*(1.0+delta))) || ((u_i/(1.0-delta) <= u) && (u <= u_i_next) && (u_prev <= u_i*(1+delta))) ) {
            
                return u_i*(1.0+delta);
            }
            i++;
        }
    }
}

I am facing the following issue. When the else if statement (the one for the DEAD ZONE) is executed many times until the value gets out of the dead zone, the code executes somewhat slowly in the beggining while when this else if statement isn't executed many times (when for example i = i - 1.0 instead of i = i - 0.001) the code is executed in a blink of an eye. I tried using breakpoints at this section in order to check if a particular instruction takes some time but this doesn't seem to be the case. Profiling the code also gave me a general idea of how much time the logarithmic_hysteretic_quantizer() function takes but this doesn't really help me to understand what's going on. Could anyone give me insight of what's going on at this section of the code ?

P.S.: I am running the code at Xcode 12.4.

Teo Protoulis
  • 203
  • 4
  • 12
  • 1
    `std::cout << "DEAD ZONE" << std::endl;` is super slow. `std::cout << "DEAD ZONE\n";` is just slow. Does that make a difference? – 463035818_is_not_an_ai Apr 28 '21 at 15:18
  • Even if I comment the whole `std::cout << "DEAD ZONE" << std::endl;` line there isn't much of a change. – Teo Protoulis Apr 28 '21 at 15:21
  • The `while` loop looks like it could be the culprit. How many iterations does that do in total when you run your program? – Ted Lyngmo Apr 28 '21 at 15:23
  • Just used a global counter to measure it. The while loop runs `3284029` times. That's a lot I think but this is how the logarithmic quantizer is working. I have to loop until I found the right interval for the value to be quantized. – Teo Protoulis Apr 28 '21 at 15:29
  • It is hard to say what you want to achieve. You use https://en.wikipedia.org/wiki/Comma_operator in `control_signal << ` line, which means: "calculate every expression, but take only the last value" (in that case `logarithmic_hysteretic_quantizer(i, control_signal(6,0), delta, u_min)`. On the other hand: did you enable compiler optimization? It is pointless to analyze a program in term of performance, when you are not using optimizations – slsy Apr 28 '21 at 15:31
  • 2
    And when I remove every `cout` call then the program takes `0.143 s` to run, which a pretty small number. I have compiled a program with `clang++ -O3 -march=native` flags, which enable high optimization as well as optimizations related to your specific CPU – slsy Apr 28 '21 at 15:35
  • 1
    And with addition of the dangerous `-ffast-math` flag (https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do) I have achieved a `0.028 s` time – slsy Apr 28 '21 at 15:38
  • @Slay, the comma-operator in this case is overloaded: http://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html#title0 -- but I agree that benchmarking code with `std::cout` inside is pointless ... – chtz Apr 28 '21 at 16:47
  • You can very likely replace the `while`-loop by solving the inequations for `u_i` and `u_i_next` and compute `i` using `log`. Due to the many branches and forced lazy-evaluation of `&&` and `||` your code may also suffer from failed branch-predictions. – chtz Apr 28 '21 at 16:58
  • Any reason you inserted many more tests compared to https://stackoverflow.com/questions/66075396/? (I will not analyze if any of these conditions actually make a difference ...) – chtz Apr 28 '21 at 17:35

0 Answers0