Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Jesse Wursten
    replied
    A new version of timeit is now available on ssc. There were three major changes.
    1. You can now calculate incremental timers. By default, timer list only gives you the total runtime of a particular timer, the timeit command also produces the runtime of the most recent iteration.
    2. Timeit now adds the relevant runtime values to r(), that is, if you type timeit 1 somename: cmd, r() will now contain the results from cmd, as well as r(t1), r(somename) and r(delta_t1). This means you can immediately process the runtimes in whichever fashion you desire.
    3. Bugfixes. The timeit command was having issues with quotes in the cmd and struggling to retain the right results in r(). The latter is surprisingly difficult. Now however, r() will contain whatever was in there before if your command did not alter r(), and whatever your command put in r() if it did do so. (As well as the timer results).
    If you use this command and get an unexpected result, please let me know. I have tried to subject it to very ludicrous commands and so far it's handled all of them, but the list is obviously not complete (e.g. I missed factor notations initially).

    Leave a comment:


  • Jesse Wursten
    replied
    Bug fix: -timeit- no longer returns an error when you use factor variable syntax (i. and so on).

    PS: If some user programmer reads this to figure out why their program is throwing errors on i. and so on, in my case it was due to the version statement, which messes with the factor variables if set to something lower than version 11.
    Last edited by Jesse Wursten; 27 Dec 2016, 14:53.

    Leave a comment:


  • Jesse Wursten
    replied
    Updates above are now on ssc, thanks as usual to the relentless Kit Baum!

    Leave a comment:


  • Jesse Wursten
    replied
    I've tried to incorporate all the suggestions.

    1. You can now specify a name as in timeit # name: cmd. The timer will be stored in scalar name.
    2. Extensive syntax checking, with automated suggestions covering most cases (if I missed any, please let me know)
    3. Any return results present will now persist through the timeit (some of the checks flush r() )
    4. The program will give a warning (but continue) if a timer is already running
    I do this by first checking the timer (e.g. r(t#) from timer list) and then checking it again after a timer off # command. If the timer was active, these times will diverge.
    5. The program will not respond to using a timer that was used before. This imo should be possible. E.g. using this in a loop.
    6. The timer will stop if the command leads to an error, or if the user presses break.

    Any more suggestions? Always welcome!

    PS: daniel klein I'm not entirely sure what you mean with the last point (capturing the rc code).
    Attached Files

    Leave a comment:


  • daniel klein
    replied
    In which situation would ("`theTimer'" == ":") be true? The second condition flags when the user didn't type a colon, right?
    If the user types

    Code:
    timeit : whatever
    omitting the timer number. Of course, the timer command later in the code will choke on this, so this check is not vital. One could think about allowing this syntax and merely listing the time instead of storing it in a timer. Something like

    Code:
    set rmsg on
    whatever
    set rmsg off
    3. I think the option to store the timer results is an interesting one. I suppose the easiest way to do this is to allow something along the lines of
    Code:
    timeit 5, name("fifthTimer"): cmd
    Code-wise that complicates things, but it's not insurmountable.
    Options seem a good idea, especially if you also want the user to explicitly specify to override a timer, that is already in use, or likewise to continue running this timer. An optional name could also be parsed as an optional second argument

    Code:
    timeit # [ name ] : cmd
    which would be easier/quicker to parse.

    4. I'm not entirely sure what you mean by multiple commands? You can prefix the same timeit command (e.g. timeit 2) to as many lines as you want, it will keep counting.
    I was thinking into the direction of, e.g., mi xeq, with syntax like

    Code:
    timeit # : cmd1 ; cmd2 [...]
    5. I'm not sure how to check if a timer is already running - timer off never returns an error and I can't think of another way to check.
    This is indeed a little effort. Here is how I would do it

    Code:
    tempname r_results
    _return hold `r_results'
    quietly timer list `theTimer'
    if (r(t`theTimer') != .) {
        display as text "timer `theTimer' already in use"
    }
    _return restore `r_results'
    6. What's the use of the nobreak? I looked it up in the help files and it seems to stop the "BREAK" command from working. It would nice to make the timer stop on -break-, but that doesn't seem to be happening with this code?
    Actually, this is bug. I want Stata to stop the timer no matter what. If I code

    Code:
    capture noisily ...
    timer off #
    I am not a hundred percent sure that Stata will run the second line of code, if the break key is pressed. That is why I enclose the commands in nobreak. However, I want to still allow the user to break the command. Therefore I should have coded

    Code:
    nobreak {
        timer on `theTimer'
            capture noisily break `0'
        timer off `theTimer'
    }
    Note the break after noisily, which temporarily turns the break key on. Even better would be capturing the return code, so I could add more stuff, including other capture prefixes, before the program ends.

    Code:
    nobreak {
        timer on `theTimer'
            capture noisily break `0'
            local Rc = _rc
        timer off `theTimer'
    }
    
    exit `Rc'
    Of course, this is, strictly speaking, no longer equivalent to

    Code:
    timer on #
    cmd
    timer off #
    because Stata needs to assign the return code to local Rc, which will take a minimum amount of time.

    Best
    Daniel
    Last edited by daniel klein; 15 Aug 2016, 09:10.

    Leave a comment:


  • Jesse Wursten
    replied
    Originally posted by daniel klein View Post
    How about

    Code:
    *! version 1.0.1 15aug2016
    program define timeit
    version 10
    
    gettoken theTimer 0 : 0 , parse(":")
    gettoken theColon 0 : 0 , parse(":")
    if ("`theTimer'" == ":") | ("`theColon'" != ":") {
    error 198
    }
    
    nobreak {
    timer on `theTimer'
    capture noisily `0'
    timer off `theTimer'
    }
    
    exit _rc
    end
    Note that the previous code would choke on

    Code:
    timeit 2 :reg y x
    if there was no blank space after the colon.

    You could add more features, like checking if a specified timer number is already in use or letting the user specify a (scalar) name, where the results are to be stored, or support multiple commands, or ... Whatever you find convenient. Just a few thoughts.

    Best
    Daniel
    First of all, thanks for the feedback!

    1. -capture noisily- seems to be what I was looking for (I was aware of capture, but without the noisily it suppresses output).
    2.
    Code:
        if ("`theTimer'" == ":") | ("`theColon'" != ":") {
            error 198
        }
    In which situation would ("`theTimer'" == ":") be true? The second condition flags when the user didn't type a colon, right?

    3. I think the option to store the timer results is an interesting one. I suppose the easiest way to do this is to allow something along the lines of
    Code:
    timeit 5, name("fifthTimer"): cmd
    Code-wise that complicates things, but it's not insurmountable.

    4. I'm not entirely sure what you mean by multiple commands? You can prefix the same timeit command (e.g. timeit 2) to as many lines as you want, it will keep counting.

    5. I'm not sure how to check if a timer is already running - timer off never returns an error and I can't think of another way to check.

    6. What's the use of the nobreak? I looked it up in the help files and it seems to stop the "BREAK" command from working. It would nice to make the timer stop on -break-, but that doesn't seem to be happening with this code?

    Thanks again!

    Leave a comment:


  • daniel klein
    replied
    How about

    Code:
    *! version 1.0.1 15aug2016
    program define timeit
        version 10
        
        gettoken theTimer 0 : 0 , parse(":")
        gettoken theColon 0 : 0 , parse(":")
        if ("`theTimer'" == ":") | ("`theColon'" != ":") {
            error 198
        }
        
        nobreak {
            timer on `theTimer'
            capture noisily `0'
            timer off `theTimer'
        }
        
        exit _rc
    end
    Note that the previous code would choke on

    Code:
    timeit 2 :reg y x
    if there was no blank space after the colon.

    You could add more features, like checking if a specified timer number is already in use or letting the user specify a (scalar) name, where the results are to be stored, or support multiple commands, or ... Whatever you find convenient. Just a few thoughts.

    Best
    Daniel

    Leave a comment:

Working...
X