in reply to Re^2: profiling XS routines
in thread profiling XS routines
but it does not work unless perl is the only process running, and the OS never schedules another task, and the OS does not run code outside perl (e.g. in kernel mode). rdtsc does not know about processes and threads in the OS. It just counts CPU clock cycles, including those spent in other applications and the kernel.
Whilst all of that is true, it is also true of pretty much every other timing method you want to name. There is no practical way of establishing exact timings with modern, deeply piped-lined, hyperthreading, multi-cored cpus running multi-tasking OSs.
With processors that perform out-of-order execution; and through hyperthreading, can interleave the instructions of 2 or more separate processes through the same core; cache-line refreshes that can stall a process for relative eons; OSs that can preempt and re-prioritise at will; compilers that re-order and/or eliminate code; there is no practical way of exactly instrumenting any single piece of code. Quite literally: No way!.
And even if there were--say by booting a highly simplified, single-tasking bootstrap kernal that just loads the CuT and times how long it takes to execute--the results would be so unrepresentative of any real-world usage as to be entirely meaningless. That's why when you read these thesis papers that optimise algorithms for maximum cache coherency and make huge claims for efficiencies, you should reach for the salt cellar.
As with any benchmarking or profiling technique that you apply on any multi-tasking OS; or any multi-cored or multi-threaded processor, the best you can do is:
Repeat the above after each code/algorithm/compile option change to obtain roughly comparible timings.
Mostly, so long as you don't do one set of timings whilst your virus scanner runs and you're listening to videos whilst playing Grand Turismo 5--and the other set whilst not--averaging an appropriate number of runs will give you a reasonable notion of whether changes you've made are moving things in the right direction or not.
That said, the three single biggest optimisations I've made in my own XS routines are: a) do as much work in each individual call as possible; b) pass any mildy sizable quantity of data by reference rather than through the stack--including largish scalars; c) if the same data is going to be passed to the XS code on multiple occasions, pack it once and pass by reference and only unpack it when you need to.
Indeed, second to a dear friends "Algorithm, algorithm, algorithm", the next best method of software optimisation is to do as little as possible! In Perl that means: don't (re)allocate memory; don't copy unnecessarially; don't make unnecessary sub/method calls; and don't convert between formats until you have to.
Those rules-of-thumb can be emphasised by running a benchmark of two essentially similar pieces of code:
sub sum1{ my @numbers = @_; my $total = 0; for my $number ( @numbers ){ $total = "$total" + "$number" } return $total };; sub sum2{ my $total = 0; $total += $_ for @{ $_[0] }; return $total };; @n = 1 .. 1e6;; cmpthese -1, { A=>q[ my $total=sum1( @n ); ], B=>q[ my $total=sum2( \@ +n ); ] };; Rate A B A 1.03/s -- -90% B 10.8/s 949% --
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^4: profiling XS routines
by syphilis (Archbishop) on Aug 30, 2009 at 01:34 UTC | |
by BrowserUk (Patriarch) on Aug 30, 2009 at 02:58 UTC | |
by BrowserUk (Patriarch) on Aug 30, 2009 at 04:40 UTC | |
by syphilis (Archbishop) on Aug 30, 2009 at 05:37 UTC |