1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- This document was generated using DocBuilder 3.3.3 -->
<HTML>
<HEAD>
<TITLE>Profiling</TITLE>
<SCRIPT type="text/javascript" src="../../doc/erlresolvelinks.js">
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF"
ALINK="#FF0000">
<CENTER>
<A HREF="http://www.erlang.se"><IMG BORDER=0 ALT="[Ericsson AB]" SRC="min_head.gif"></A>
</CENTER>
<A NAME="8"><!-- Empty --></A>
<H2>8 Profiling</H2>
<A NAME="8.1"><!-- Empty --></A>
<H3>8.1 Do not guess about performance, when you can know!</H3>
<P>If you have time critical code that is running too slow. Do not
waste your time trying to guess what might be slowing it
down. The best approach is to profile your code to find the
bottlenecks and concentrate your efforts on optimizing
them. Profiling Erlang code is in first hand done with the tools
<CODE>fprof</CODE> and <CODE>eprof</CODE>. But also the tools <CODE>cover</CODE>
and <CODE>cprof</CODE> may be useful.
<P>
<TABLE CELLPADDING=4>
<TR>
<TD VALIGN=TOP><IMG ALT="Note!" SRC="note.gif"></TD>
<TD>
<P> Do not optimize code that is not time critical. When
time is not of the essence it is not worth the trouble trying
to gain a few microseconds here and there. In this case it
will never make a notable difference. </TD>
</TR>
</TABLE>
<A NAME="8.2"><!-- Empty --></A>
<H3>8.2 Big systems</H3>
<P> If you have a big system it might be interesting to run profiling
on a simulated an limited scenario to start with. But bottlenecks
has a tendency to only appear or cause problems, when
there are many things going on at the same time, and when there
are many nodes involved. Therefore it is desirable to also run
profiling in a system test plant on a real target system.
<P>When your system is big you do not want to run the profiling
tools on the whole system. You want to concentrate on processes
and modules that you know are central and stand for a big part of the
execution.
<A NAME="8.3"><!-- Empty --></A>
<H3>8.3 What to look for</H3>
<P> When analyzing the result file from the profiling activity
you will in first hand look for functions that are called many
times and has a long "own execution time" (time excluded calls
to other functions). Functions that just are called very
many times can also be interesting, as even small things can add
up to quite a bit if they are repeated often. Then you need to
ask yourself what can I do to reduce this time. Appropriate
types of questions to ask yourself are:
<P>
<UL>
<LI>
Can I reduce the number of times the function is called?
</LI>
<LI>
Are there tests that can be run less often if I change
the order of tests?
</LI>
<LI>
Are there redundant tests that can be removed?
</LI>
<LI>
Is there some expression calculated giving the same result
each time?
</LI>
<LI>
Is there other ways of doing this that are equivalent and
more efficient?
</LI>
<LI>
Can I use another internal data representation to make
things more efficient?
</LI>
</UL>
<P>These questions are not always trivial to answer. You might
need to do some benchmarks to back up your theory, to avoid
making things slower if your theory is wrong. See <A HREF="#benchmark"> benchmarking</A>.<A NAME="8.4"><!-- Empty --></A>
<H3>8.4 Tools</H3>
<A NAME="8.4.1"><!-- Empty --></A>
<H4>8.4.1 fprof</H4>
<P> <CODE>fprof</CODE> measures the execution time for each function,
both own time i.e how much time a function has used for its
own execution, and accumulated time i.e. including called
functions. The values are displayed per process. You also get
to know how many times each function has been
called. <CODE>fprof</CODE> is based on trace to file in order to
minimize runtime performance impact. Using fprof is just a
matter of calling a few library functions, see fprof manual
page under the application tools.
<P> <CODE>fprof</CODE> is introduced in version R8 of Erlang/OTP. Its
predecessor <CODE>eprof</CODE> that is based on the Erlang trace BIFs,
is still available, see eprof manual page under the
application tools. Eprof shows how much time has been used by
each process, and in which function calls this time has been
spent. Time is shown as percentage of total time, not as
absolute time.
<A NAME="8.4.2"><!-- Empty --></A>
<H4>8.4.2 cover</H4>
<P> <CODE>cover</CODE>'s primary use is coverage analysis to verify
test cases, making sure all relevant code is covered.
<CODE>cover</CODE> counts how many times each executable line of
code is executed when a program is run. This is done on a per
module basis. Of course this information can be used to
determine what code is run very frequently and could therefore
be subject for optimization. Using cover is just a matter of
calling a few library functions, see cover manual
page under the application tools.
<A NAME="8.4.3"><!-- Empty --></A>
<H4>8.4.3 cprof</H4>
<P> <CODE>cprof</CODE> is something in between <CODE>fprof</CODE> and
<CODE>cover</CODE> regarding features. It counts how many times each
function is called when the program is run, on a per module
basis. <CODE>cprof</CODE> has a low performance degradation (versus
<CODE>fprof</CODE> and <CODE>eprof</CODE>) and does not need to recompile
any modules to profile (versus <CODE>cover</CODE>).
<A NAME="8.4.4"><!-- Empty --></A>
<H4>8.4.4 Tool summarization</H4>
<P>
<CENTER>
<TABLE CELLSPACING=0 CELLPADDING=2 BORDER=1>
<CAPTION ALIGN=BOTTOM><EM> </EM></CAPTION>
<TR>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Tool
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Results
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Size of result
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Effects on program
execution time
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Records number of calls
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Records Execution time
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Records called by
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Records garbage collection
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE> fprof </CODE>
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
per process to screen/file
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
large
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
slowdown
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
total and own
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE> eprof </CODE>
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
per process/function to screen/file
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
medium
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
significant slowdown
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
only total
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE> cover </CODE>
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
per module to screen/file
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
small
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
moderate slowdown
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes, per line
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE> cprof </CODE>
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
per module to caller
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
small
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
small slowdown
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
yes
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
no
</TD>
</TR>
</TABLE>
</CENTER>
<A NAME="benchmark"><!-- Empty --></A><A NAME="8.5"><!-- Empty --></A>
<H3>8.5 Benchmarking</H3>
<P>A benchmark is mainly a way to compare different constructs
that logically have the same effect. In other words you can
take two sequential algorithms and see which one is most
efficient. This is achieved by measuring the execution time of
several invocations of the algorithms and then comparing the
result. However measuring runtime is far from an exact
science, and running the same benchmark two times in a row
might not give exactly the same figures. Although the trend will
be the same, so you may draw a conclusion such as: Algorithm A
is substantially faster than B, but you can not say that:
Algorithm A is exactly 3 times faster than B.
<P>If you want to write a benchmark program yourself
there are a few things you must consider in order to get
meaningful results.
<P>
<UL>
<LI>
The total execution time should be at least several
seconds
</LI>
<LI>
That any time spent in setup before entering the
measurement loop is very small compared to the total
time.
</LI>
<LI>
That time spent by the loop itself is small compared to
the total execution time.
</LI>
</UL>
<P>To help you with this we provide a benchmarking framework
located in the doc/efficiency_guide directory of the Erlang/OTP
installation, which consists
of <A TARGET="_top" HREF="bench.erl">bench.erl</A>
,
<A TARGET="_top" HREF="bench.hrl">bench.hrl</A>
,
and <A TARGET="_top" HREF="all.erl">all.erl</A>
. To
find out how it works please consult
<A TARGET="_top" HREF="README">README</A>
, you can
also look at the example benchmark:
<A TARGET="_top" HREF="call_bm.erl">call_bm.erl</A>
.
Here follows an example of running the benchmark defined in
<CODE>call_bm.erl</CODE> in a unix environment:
<PRE>
unix_prompt> ls
all.erl bench.erl bench.hrl call_bm.erl
unix_prompt> erl
Erlang (BEAM) emulator version 5.1.3 [threads:0]
Eshell V5.1.3 (abort with ^G)
1> c(bench).
{ok,bench}
2> bench:run().
Compiling call_bm.erl...
Running call_bm: local_call external_call fun_call apply_fun apply_mfa
ok
3> halt().
unix_prompt> ls
all.erl bench.erl bench.hrl call_bm.erl index.html
unix_prompt>
</PRE>
<P>The resulting index.html file may look like:
<A TARGET="_top" HREF="call_result.html">index.html</A>
.
<P>
<TABLE CELLPADDING=4>
<TR>
<TD VALIGN=TOP><IMG ALT="Note!" SRC="note.gif"></TD>
<TD>
<P>The results of a benchmark can only be considered
valid for the Erlang/OTP version that you run the benchmark
on. Performance is dependent on the implementation which may
change between releases. </TD>
</TR>
</TABLE>
<CENTER>
<HR>
<SMALL>
Copyright © 1991-2006
<A HREF="http://www.erlang.se">Ericsson AB</A><BR>
</SMALL>
</CENTER>
</BODY>
</HTML>
|