Slow it down to speed it up



  • It's 5AM on July 5 and I've just finished a long debugging session...

    Out application can crudely be described as follows:

      - wait for request
      - make blocking socket request to another program to read lots of data from db
      - crunch data
      - insert data to db
      - repeat
    

    Last time around, I sped up the crunching from several minutes to several seconds. This time I was supposed to speed up the data save. I changed it from:

      - call db to get next sequence value
      - call db to insert one row
      - repeat 10K times
    

    to:

      - alter sequences to increment by 100K, and cache range in thread-safe manner
      - build 1 struct to contain data representing 10K rows
      - call 1 stored proc to grind through the struct
    

    ...which reduced the save-time from several minutes to less than 20ms. This caused the application to take twice as long to run. WTF?!

    Out application was designed by folks who firmly believe in using the decapsulation design pattern; all data is global and everything that modifies it is scattered across the application. This guarantees that the entire application is extremely fragile, and that any attempt to change something will surely miss some aspect of what needs to be changed.

    After a lot of debugging, it occurred to me that the application was now spending 90+% of its time waiting for the other application to return the results of the queries. I reasoned that perhaps it was now running so quickly that it had lapped itself and was tripping over its own feet.

    I added a 30 second sleep just after the single stored procedure call (to simulate some of the time that used to be spent making 10K+ db calls) to give the rest of the system a chance to "settle".

    Bingo.

    I originally asked them to let me rewrite that query-application as part of this speedup, but was told no because it was designed that way on purpose.

    Maybe now they'll let me rewrite it.



  • @snoofle said:

    I originally asked them to let me rewrite that query-application as part of this speedup, but was told no because it was designed that way on purpose.
     

    It was designed with decapsulation in mind?

    Never mind design principles, won't that violate some data confidentiality policy at your place?  I'm sure if you flagged it up as an integrity and security issue, they'd sit pu and take note (when the sound of hefty fines come crashing through windows).



  • @snoofle said:

    I added a 30 second sleep

    Should have used a [url=http://thedailywtf.com/Articles/The-Speedup-Loop.aspx]speed-up loop[/url].


  • Discourse touched me in a no-no place

    @Cassidy said:

    It was designed with decapsulation in mind?

    Snoofle can confirm or deny that on his own but it's been my experience that most code is written that way, and not necessarily by design, but simply because proper scoping is apparently beyond most people.



  • @FrostCat said:

    it's been my experience that most code is written that way, and not necessarily by design, but simply because proper scoping is apparently beyond most people.
     

    My experience too, but mainly from novice coders. I believe some industries are governed by a policy that determines coding standards (must be defensive, proper encapsulation, levels of encryption) - particularly the financial industry, so code like this will be subject to some examination and QA process.

    Perhaps that just indicates snoofies ain't working for a financial institution (although US compliance differs from UK and all that).



  • Sounds like a locking/contention/transaction issue (something is blocking another thead(s) from executing).

    Maybe there was an unintentional race condition introduced when you sped things up? Not that you'll ever find out, because it sounds like they don't really like profilers.



  • @FrostCat said:

    Snoofle can confirm or deny that on his own but it's been my experience that most code is written that way, and not necessarily by design, but simply because proper scoping is apparently beyond most people.
     

    Decapsulation was intentional because these idiots developers simply do not comprehend the word encapsulation.

     



  • @snoofle said:

    @FrostCat said:

    Snoofle can confirm or deny that on his own but it's been my experience that most code is written that way, and not necessarily by design, but simply because proper scoping is apparently beyond most people.
     

    Decapsulation was intentional because these idiots developers simply do not comprehend the word encapsulation.

     

    My favourite thing to see when inheriting an exiting pile of shit code base is a class called Globals. Yay!



  • @C-Octothorpe said:

    My favourite thing to see when inheriting an exiting pile of shit code base is a class called Globals. Yay!
    Don't even try to pretend that globals aren't necessary a whole hell of a lot of the time.

     



  • @Zylon said:

    @C-Octothorpe said:

    My favourite thing to see when inheriting an exiting pile of shit code base is a class called Globals. Yay!
    Don't even try to pretend that globals aren't necessary a whole hell of a lot of the time.

     

    Sure, they're called configuration settings. :)



  • @C-Octothorpe said:

    Sure, they're called configuration settings. :)
     

    .. or finals.

    Global constants, yup. Global variables... UR DOIN IT RONG.



  • @snoofle said:

    idiots developers
    I usually refer to these as duhvelopers (emphasis on the duh).



  • @snoofle said:

    I added a 30 second sleep just after the single stored procedure call (to simulate some of the time that used to be spent making 10K+ db calls) to give the rest of the system a chance to "settle".

    Bingo.

    A poorly designed system is like a fan on a computer case that has accumulated dust for years; removing the dust suddenly will cause a shift in weight and possibly change the pressure pattern on the bearings, making the fan less efficient or breaking it entirely.


  • Discourse touched me in a no-no place

    @Cassidy said:

    Global variables... UR DOIN IT RONG.
    Oh yes - I remember this one; I had to change an OSS program to be able to shockhorror* be able to cope with more than one instance of what it was designed to do (telnet as I seem to recall.) Our options were to re-write the code (pointless, since the reason we were using the code to begin with was to NOT reinvent triangular wheels) or stuff all the global variables into a
    struct global {....}
    and start passing that around for each instance. Not fun.



    (I don't quite remember the actual details, but we needed to communicate with one or more boxes, and the only protocol available/useful to us was telnet, and running separate instances of an actual telnet application wasn't an option.)



  • @PJH said:

    @Cassidy said:
    Global variables... UR DOIN IT RONG.
    Oh yes - I remember this one; I had to change an OSS program to be able to shockhorror* be able to cope with more than one instance of what it was designed to do (telnet as I seem to recall.) Our options were to re-write the code (pointless, since the reason we were using the code to begin with was to NOT reinvent triangular wheels) or stuff all the global variables into a
    struct global {....}
    and start passing that around for each instance. Not fun.



    (I don't quite remember the actual details, but we needed to communicate with one or more boxes, and the only protocol available/useful to us was telnet, and running separate instances of an actual telnet application wasn't an option.)
    Cool story bro, however for the remaining 99.998% of cases, using global variables is a good indicator of a really bad code smell.



  • @C-Octothorpe said:

    @PJH said:
    @Cassidy said:
    Global variables... UR DOIN IT RONG.
    Oh yes - I remember this one; I had to change an OSS program to be able to shockhorror* be able to cope with more than one instance of what it was designed to do (telnet as I seem to recall.) Our options were to re-write the code (pointless, since the reason we were using the code to begin with was to NOT reinvent triangular wheels) or stuff all the global variables into a
    struct global {....}
    and start passing that around for each instance. Not fun.



    (I don't quite remember the actual details, but we needed to communicate with one or more boxes, and the only protocol available/useful to us was telnet, and running separate instances of an actual telnet application wasn't an option.)
    Cool story bro, however for the remaining 99.998% of cases, using global variables is a good indicator of a really bad code smell.

    I don't think PJH was saying globals were a good idea.  I believe the point is, sometimes, if you have a program that's rife with globals and you need to fix that, sometimes, the best approach is to make a class called globals or the nearest equivalent.  Note that when this methodology is used to fix such a program, the class is not well-named, in the sense that the class really isn't globals.  However, anyone thinking along the lines the program was originally written in will handle seeing what used to be global variables being in a globals class than they will handle them being in a config_options class.

    In fact, I got the feeling that PJH was saying globals were a bad idea, but they frequently exist in code bases and one has to work around that. And that's not fun.



  • @tgape said:

    I don't think PJH was saying globals were a good idea. 

    ...

    In fact, I got the feeling that PJH was saying globals were a bad idea, but they frequently exist in code bases and one has to work around that. And that's not fun.

     

    My impression, too.

    @tgape said:

    I believe the point is, sometimes, if you have a program that's rife with globals and you need to fix that, sometimes, the best approach is to make a class called globals or the nearest equivalent.

    It's an approach, and it's part-way along the journey... but you're still far from the destination.

     


  • Discourse touched me in a no-no place

    @C-Octothorpe said:

    Cool story bro, however for the remaining 99.998% of cases, using global variables is a good indicator of a really bad code smell.
    You appear to be contradicting me. You're not. The program was badly written to begin with.


  • Garbage Person

    @PJH said:

    @Cassidy said:
    Global variables... UR DOIN IT RONG.
    Oh yes - I remember this one; I had to change an OSS program to be able to *shock*horror* be able to cope with more than one instance of what it was designed to do (telnet as I seem to recall.) Our options were to re-write the code (pointless, since the reason we were using the code to begin with was to NOT reinvent triangular wheels) or stuff all the global variables into a

    struct global {....}

    and start passing that around for each instance. Not fun.

    (I don't quite remember the actual details, but we needed to communicate with one or more boxes, and the only protocol available/useful to us was telnet, and running separate instances of an actual telnet application wasn't an option.)

     

     

    You were using third party code for a telnet client? You do realize that you could have just opened a socket and read/wrote bytes to it, right? Telnet isn't so much a protocol as a fucking bare socket with a semantic meaning serverside of "redirect me a console plz"

     


  • Discourse touched me in a no-no place

    @Weng said:

    You were using third party code for a telnet client? You do realize that you could have just opened a socket and read/wrote bytes to it, right? Telnet isn't so much a protocol as a fucking bare socket with a semantic meaning serverside of "redirect me a console plz"
    How naive. There are at least 10 RFC's relevant to the telnet protocol. Any particular ones you recommend I drop in favour of simply opening a SOCK_DGRAM with third party (buggy as it turned out) servers with which we have no input as to how they behave?


Log in to reply