Lumpi
Lumpi

Reputation: 2821

Is it faster to use one large EXPR in tcl rather than several small ones

I have a proc which gets executed a couple of hundred thousand times:

proc ::TsaiWu { x_all_comp x_all_tens y_all_comp y_all_tens s_allow x_stress y_stress s_stress } {

        set FX  [ expr { 1 / $x_all_tens - 1 / $x_all_tens } ]
        set FY  [ expr { 1 / $y_all_tens - 1 / $y_all_tens } ] 
        set FXX [ expr { 1 / ( $x_all_tens * $x_all_comp ) } ]
        set FYY [ expr { 1 / ( $y_all_tens * $y_all_comp ) } ]
        set IXY [ expr { -0.5 * sqrt( ( $y_all_tens * $y_all_comp) / ( $x_all_tens * $x_all_comp) ) } ]
        set FXY [ expr { $IXY / sqrt( $x_all_tens * $x_all_comp * $y_all_tens * $y_all_comp ) } ]
        set FSS [ expr { 1 / pow($s_allow,2) } ]
        set a   [ expr { $FXX * pow($x_stress,2) + $FYY * pow($y_stress,2) + 2 * $FXY * $x_stress * $y_stress + $FSS * pow($s_stress,2) } ]
        set b   [ expr { $FX * $x_stress + $FY * $y_stress } ]
        set TW  [ expr { $a + $b } ]
        set SR  [ expr { ( -2 + sqrt( pow($b,2) + 4 * $a) ) / ( 2 * $a ) } ]

        set result [ list $TW $SR ] 

    return $result

 }

What possibilties do I have to speed it up? I have added curly brackets to the expression, that did help a lot.. Is it faster to rewrite the single equations into just two (one for TW and one for SR) ? Then I would only need to call expr twice. Would it be faster if i wrote this piece of code in c++ and somehow use in my tcl script? Is there a speed difference between sqrt and pow(x,0.5) ? Any tips on how to speed this proc upp are welcome! In the final version i will use upvar or a global variable so I dont't have to hand over the result as a list copy (is it much slower?) Would the code run faster if I would not put these lines in a proc by itselv, and insted place it "inline" the code where it is needed? As far as I know procs are faster in TCl...

Upvotes: 0

Views: 679

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137637

Provided you brace your expressions (important!) and use just local variables, it makes very little difference. The cost of reading and writing a local variable is minimal, not much more than reading and writing a variable in C. The real costs of execution will mainly be in the arithmetic operations and the function calls; it is those that you should minimize (while retaining correctness, of course).

Specific issues: You might find that using $b**2 or $b*$b is cheaper than pow($b,2). The sqrt() calls are likely to be expensive; can you reduce the number that you do? (Note that pow(…,0.5) is unlikely to be better, and might possibly be worse in terms of numerical accuracy.)

Generic issues: Changing the build of Tcl can have quite a big effect. I found a few weeks ago that switching from the system build of 8.5.9 to my own (made with an up-to-date LLVM/Clang) made a substantial improvement to speeds, yet with the identical source code and identical scripts. Funny how these things go…

If you're really hurting for time, try writing a little C code to implement the math. That will probably be faster (and will allow you to use float instead of being forced to use double, which is what Tcl uses internally for floating-point numbers) but I don't know how much faster. If you're doing this, you'll find the API calls Tcl_GetDoubleFromObj and Tcl_NewDoubleObj to be useful.

Upvotes: 2

Don Porter
Don Porter

Reputation: 21

If you use tcl::unsupported::disassemble to examine the bytecode of the proc, you will see that one [expr] vs many [expr] makes no difference at all.

When you [time] make sure to test a large number of iterations so that you measure the run time, and not the compile-to-bytecode time which happens only once.

Your concern about "list copy" on return is unfounded. That's not how Tcl works. Toying with [upvar] to solve a "problem" you do not actually have is not a path you want to take.

Using a global variable will slow your proc down, possibly measurably. You want your [expr]essions in a proc so they can operate on local vars, where the speed gains of bytecode are the greatest.

Upvotes: 2

Related Questions