|
|
(2 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
− | ''How fast is '''equationReader'''?'' | + | This project has migrated over to '''github'''. |
| | | |
− | Preliminary results are in, and they are a little disappointing. '''equationReader''' seems to take between 10 to 20 times longer than a hard-coded solution, depending on the equation involved, and the type of evaluation. I will upload results of my experiment when I have the time. If you don't plan on using it within your main solver loop, this isn't a big deal, but if you do, the question is: do the benefits of flexibility outweigh the cost?
| + | '''''[http://github.com/Marupio/equationReader/wiki Click here for the new website.]''''' |
| | | |
− | Also, expect '''equationReader''' to get faster with future updates. I used a ''function-pointer'' framework, and should have used a ''function object''... or maybe even defined an entire set of derived objects, one for each operation type, and inlined its <tt>evaluate</tt> function.
| + | http://github.com/Marupio/equationReader/wiki |
− | | + | |
− | == Efficiency discussion ==
| + | |
− | | + | |
− | === Parsing and evaluating ===
| + | |
− | There is a difference between ''parsing'' and ''evaluating''. When the equation is first read, it is a ''human-readable'' string expression. '''equationReader''' translates the ''human-readable'' form into an ''operation list''. This is ''parsing''. To calculate the result, '''equationReader''' does a <tt>forAll(operations, i)</tt>. This is ''evaluating''.
| + | |
− | | + | |
− | ''Parsing'' happens only once, and is slow. ''Evaluating'' happens at every cell index, at every timestep (or however you've used it), and it is fast.
| + | |
− | | + | |
− | === Burn all conditionals ===
| + | |
− | Conditionals are slow. In the framework of '''equationReader''', one <tt>if</tt> or <tt>switch</tt> slows a single equation operation by about 25%. A word comparison - that slows things by over 1600%.
| + | |
− | | + | |
− | '''equationReader''' has a design philosophy: put no conditionals in the way of an <tt>evaluate</tt> function. To achieve this I implemented a ''function-pointer'' framework.
| + | |
− | | + | |
− | === Function-pointers ===
| + | |
− | Apparently in C++ you can have pointers to functions. The syntax looks a little odd:
| + | |
− | | + | |
− | void (Foam::equationReader::*reportScalarOperationFunction_)
| + | |
− | (
| + | |
− | const label&,
| + | |
− | const label&
| + | |
− | ) const;
| + | |
− | | + | |
− | That's not a function - it's a pointer. You don't see these too often because C++'s ''virtual functions'' do the same thing - only you need a hierarchy of derived classes. In theory, ''virtual functions'' have slightly more overhead than ''function-pointers'' because each ''virtual function'' call requires a hash-table look-up, unlike the direct use of ''function-pointers''.
| + | |
− | | + | |
− | Anyway, these ''function pointers'' can all be assigned during ''parsing'', and called directly during ''evaluation''. Essentially this moves all conditionals into the parser, and their result is permanently remembered. In short: these make '''equationReader''' faster.
| + | |
− | | + | |
− | Now, there's not a single conditional encountered during an ''evaluate'' function call. Even all the <tt>debug</tt> switches have been converted to ''function-pointers''.
| + | |
− | | + | |
− | === Function objects ===
| + | |
− | Apparently ''function-pointers'' are old-school, and the next best thing are ''function-objects'', or "''functors''". ''Function-objects'' are better because they can be inlined, unlike ''function-pointers''. Well, I didn't get the memo until it was too late for this version. Maybe in another version.
| + | |