Sophie

Sophie

distrib > Fedora > 17 > i386 > by-pkgid > 675c8c8167236dfcf8d66da674f931e8 > files > 43

erlang-doc-R15B-03.3.fc17.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../otp_doc.css" type="text/css">
<title>Erlang -- Constructing and matching binaries</title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"><div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="../js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript">
            <!--
              function getWinHeight() {
                var myHeight = 0;
                if( typeof( window.innerHeight ) == 'number' ) {
                  //Non-IE
                  myHeight = window.innerHeight;
                } else if( document.documentElement && ( document.documentElement.clientWidth ||
                                                         document.documentElement.clientHeight ) ) {
                  //IE 6+ in 'standards compliant mode'
                  myHeight = document.documentElement.clientHeight;
                } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                  //IE 4 compatible
                  myHeight = document.body.clientHeight;
                }
                return myHeight;
              }

              function setscrollpos() {
                var objf=document.getElementById('loadscrollpos');
                 document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
              }

              function addEvent(obj, evType, fn){
                if (obj.addEventListener){
                obj.addEventListener(evType, fn, true);
                return true;
              } else if (obj.attachEvent){
                var r = obj.attachEvent("on"+evType, fn);
                return r;
              } else {
                return false;
              }
             }

             addEvent(window, 'load', setscrollpos);

             //--></script><div id="leftnav"><div class="innertube">
<img alt="Erlang logo" src="../erlang-logo.png"><br><small><a href="users_guide.html">User's Guide</a><br><a href="../pdf/otp-system-documentation-5.9.3.1.pdf">PDF</a><br><a href="../index.html">Top</a></small><p><strong>Efficiency Guide</strong><br><strong>User's Guide</strong><br><small>Version 5.9.3.1</small></p>
<br><a href="javascript:openAllFlips()">Expand All</a><br><a href="javascript:closeAllFlips()">Contract All</a><p><small><strong>Chapters</strong></small></p>
<ul class="flipMenu" imagepath="../js/flipmenu">
<li id="no" title="Introduction" expanded="false">Introduction<ul>
<li><a href="introduction.html">
              Top of chapter
            </a></li>
<li title="Purpose"><a href="introduction.html#id62954">Purpose</a></li>
<li title="Prerequisites"><a href="introduction.html#id65420">Prerequisites</a></li>
</ul>
</li>
<li id="no" title="The Eight Myths of Erlang Performance" expanded="false">The Eight Myths of Erlang Performance<ul>
<li><a href="myths.html">
              Top of chapter
            </a></li>
<li title="Myth: Funs are slow"><a href="myths.html#id64448">Myth: Funs are slow</a></li>
<li title="Myth: List comprehensions are slow"><a href="myths.html#id61406">Myth: List comprehensions are slow</a></li>
<li title="Myth: Tail-recursive functions are MUCH faster
    than recursive functions"><a href="myths.html#id62291">Myth: Tail-recursive functions are MUCH faster
    than recursive functions</a></li>
<li title="Myth: '++' is always bad"><a href="myths.html#id60058">Myth: '++' is always bad</a></li>
<li title="Myth: Strings are slow"><a href="myths.html#id62534">Myth: Strings are slow</a></li>
<li title="Myth: Repairing a Dets file is very slow"><a href="myths.html#id61135">Myth: Repairing a Dets file is very slow</a></li>
<li title="Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)"><a href="myths.html#id64006">Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)</a></li>
<li title="Myth: Use '_' to speed up your program when a variable is not used"><a href="myths.html#id64026">Myth: Use '_' to speed up your program when a variable is not used</a></li>
</ul>
</li>
<li id="no" title="Common Caveats" expanded="false">Common Caveats<ul>
<li><a href="commoncaveats.html">
              Top of chapter
            </a></li>
<li title="The timer module"><a href="commoncaveats.html#id62547">The timer module</a></li>
<li title="list_to_atom/1"><a href="commoncaveats.html#id61885">list_to_atom/1</a></li>
<li title="length/1"><a href="commoncaveats.html#id60806">length/1</a></li>
<li title="setelement/3"><a href="commoncaveats.html#id58300">setelement/3</a></li>
<li title="size/1"><a href="commoncaveats.html#id65402">size/1</a></li>
<li title="split_binary/2"><a href="commoncaveats.html#id60836">split_binary/2</a></li>
<li title="The '--' operator"><a href="commoncaveats.html#id61766">The '--' operator</a></li>
</ul>
</li>
<li id="loadscrollpos" title="Constructing and matching binaries" expanded="true">Constructing and matching binaries<ul>
<li><a href="binaryhandling.html">
              Top of chapter
            </a></li>
<li title="How binaries are implemented"><a href="binaryhandling.html#id62932">How binaries are implemented</a></li>
<li title="Constructing binaries"><a href="binaryhandling.html#id66066">Constructing binaries</a></li>
<li title="Matching binaries"><a href="binaryhandling.html#id63610">Matching binaries</a></li>
</ul>
</li>
<li id="no" title="List handling" expanded="false">List handling<ul>
<li><a href="listHandling.html">
              Top of chapter
            </a></li>
<li title="Creating a list"><a href="listHandling.html#id66709">Creating a list</a></li>
<li title="List comprehensions"><a href="listHandling.html#id66805">List comprehensions</a></li>
<li title="Deep and flat lists"><a href="listHandling.html#id66875">Deep and flat lists</a></li>
<li title="Why you should not worry about recursive lists functions"><a href="listHandling.html#id67017">Why you should not worry about recursive lists functions</a></li>
</ul>
</li>
<li id="no" title="Functions" expanded="false">Functions<ul>
<li><a href="functions.html">
              Top of chapter
            </a></li>
<li title="Pattern matching"><a href="functions.html#id67142">Pattern matching</a></li>
<li title="Function Calls "><a href="functions.html#id67362">Function Calls </a></li>
<li title="Memory usage in recursion"><a href="functions.html#id67506">Memory usage in recursion</a></li>
</ul>
</li>
<li id="no" title="Tables and databases" expanded="false">Tables and databases<ul>
<li><a href="tablesDatabases.html">
              Top of chapter
            </a></li>
<li title="Ets, Dets and Mnesia"><a href="tablesDatabases.html#id67596">Ets, Dets and Mnesia</a></li>
<li title="Ets specific"><a href="tablesDatabases.html#id67983">Ets specific</a></li>
<li title="Mnesia specific"><a href="tablesDatabases.html#id68087">Mnesia specific</a></li>
</ul>
</li>
<li id="no" title="Processes" expanded="false">Processes<ul>
<li><a href="processes.html">
              Top of chapter
            </a></li>
<li title="Creation of an Erlang process"><a href="processes.html#id68191">Creation of an Erlang process</a></li>
<li title="Process messages"><a href="processes.html#id68339">Process messages</a></li>
<li title="The SMP emulator"><a href="processes.html#id68531">The SMP emulator</a></li>
</ul>
</li>
<li id="no" title="Drivers" expanded="false">Drivers<ul>
<li><a href="drivers.html">
              Top of chapter
            </a></li>
<li title="Drivers and concurrency"><a href="drivers.html#id68634">Drivers and concurrency</a></li>
<li title="Avoiding copying of binaries when calling a driver"><a href="drivers.html#id68675">Avoiding copying of binaries when calling a driver</a></li>
<li title="Returning small binaries from a driver"><a href="drivers.html#id68743">Returning small binaries from a driver</a></li>
<li title="Returning big binaries without copying from a driver"><a href="drivers.html#id68777">Returning big binaries without copying from a driver</a></li>
</ul>
</li>
<li id="no" title="Advanced" expanded="false">Advanced<ul>
<li><a href="advanced.html">
              Top of chapter
            </a></li>
<li title="Memory"><a href="advanced.html#id68919">Memory</a></li>
<li title="System limits"><a href="advanced.html#id69276">System limits</a></li>
</ul>
</li>
<li id="no" title="Profiling" expanded="false">Profiling<ul>
<li><a href="profiling.html">
              Top of chapter
            </a></li>
<li title="Do not guess about performance - profile"><a href="profiling.html#id69579">Do not guess about performance - profile</a></li>
<li title="Big systems"><a href="profiling.html#id69661">Big systems</a></li>
<li title="What to look for"><a href="profiling.html#id69681">What to look for</a></li>
<li title="Tools"><a href="profiling.html#id69738">Tools</a></li>
<li title="Benchmarking"><a href="profiling.html#id70245">Benchmarking</a></li>
</ul>
</li>
</ul>
</div></div>
<div id="content">
<div class="innertube">
<h1>4 Constructing and matching binaries</h1>
  

  <p>In R12B, the most natural way to write binary construction and matching is now
  significantly faster than in earlier releases.</p>

  <p>To construct at binary, you can simply write</p>

  <p><strong>DO</strong> (in R12B) / <strong>REALLY DO NOT</strong> (in earlier releases)</p>
  <div class="example"><pre>
my_list_to_binary(List) -&gt;
    my_list_to_binary(List, &lt;&lt;&gt;&gt;).

my_list_to_binary([H|T], Acc) -&gt;
    my_list_to_binary(T, &lt;&lt;Acc/binary,H&gt;&gt;);
my_list_to_binary([], Acc) -&gt;
    Acc.</pre></div>  

  <p>In releases before R12B, <span class="code">Acc</span> would be copied in every iteration.
  In R12B, <span class="code">Acc</span> will be copied only in the first iteration and extra
  space will be allocated at the end of the copied binary. In the next iteration,
  <span class="code">H</span> will be written in to the extra space. When the extra space runs out,
  the binary will be reallocated with more extra space.</p>

  <p>The extra space allocated (or reallocated) will be twice the size of the
  existing binary data, or 256, whichever is larger.</p>

  <p>The most natural way to match binaries is now the fastest:</p>

  <p><strong>DO</strong> (in R12B)</p>
  <div class="example"><pre>
my_binary_to_list(&lt;&lt;H,T/binary&gt;&gt;) -&gt;
    [H|my_binary_to_list(T)];
my_binary_to_list(&lt;&lt;&gt;&gt;) -&gt; [].</pre></div>  

  <h3><a name="id62932">4.1 
        How binaries are implemented</a></h3>
    

    <p>Internally, binaries and bitstrings are implemented in the same way.
    In this section, we will call them <strong>binaries</strong> since that is what
    they are called in the emulator source code.</p>

    <p>There are four types of binary objects internally. Two of them are
    containers for binary data and two of them are merely references to
    a part of a binary.</p>

    <p>The binary containers are called <strong>refc binaries</strong>
    (short for <strong>reference-counted binaries</strong>) and <strong>heap binaries</strong>.</p>

    <p><a name="refc_binary"></a><strong>Refc binaries</strong>
    consist of two parts: an object stored on
    the process heap, called a <strong>ProcBin</strong>, and the binary object itself
    stored outside all process heaps.</p>

    <p>The binary object can be referenced by any number of ProcBins from any
    number of processes; the object contains a reference counter to keep track
    of the number of references, so that it can be removed when the last
    reference disappears.</p>

    <p>All ProcBin objects in a process are part of a linked list, so that
    the garbage collector can keep track of them and decrement the reference
    counters in the binary when a ProcBin disappears.</p>

    <p><a name="heap_binary"></a><strong>Heap binaries</strong> are small binaries,
    up to 64 bytes, that are stored directly on the process heap.
    They will be copied when the process
    is garbage collected and when they are sent as a message. They don't
    require any special handling by the garbage collector.</p>

    <p>There are two types of reference objects that can reference part of
    a refc binary or heap binary. They are called <strong>sub binaries</strong> and
    <strong>match contexts</strong>.</p>

    <p><a name="sub_binary"></a>A <strong>sub binary</strong>
    is created by <span class="code">split_binary/2</span> and when
    a binary is matched out in a binary pattern. A sub binary is a reference
    into a part of another binary (refc or heap binary, never into a another
    sub binary). Therefore, matching out a binary is relatively cheap because
    the actual binary data is never copied.</p>

    <p><a name="match_context"></a>A <strong>match context</strong> is
    similar to a sub binary, but is optimized
    for binary matching; for instance, it contains a direct pointer to the binary
    data. For each field that is matched out of a binary, the position in the
    match context will be incremented.</p>

    <p>In R11B, a match context was only used during a binary matching
    operation.</p>

    <p>In R12B, the compiler tries to avoid generating code that
    creates a sub binary, only to shortly afterwards create a new match
    context and discard the sub binary. Instead of creating a sub binary,
    the match context is kept.</p>

    <p>The compiler can only do this optimization if it can know for sure
    that the match context will not be shared. If it would be shared, the
    functional properties (also called referential transparency) of Erlang
    would break.</p>
  

  <h3><a name="id66066">4.2 
        Constructing binaries</a></h3>
    

    <p>In R12B, appending to a binary or bitstring</p>

  <div class="example"><pre>
&lt;&lt;Binary/binary, ...&gt;&gt;
&lt;&lt;Binary/bitstring, ...&gt;&gt;</pre></div>

    <p>is specially optimized by the <strong>run-time system</strong>.
    Because the run-time system handles the optimization (instead of
    the compiler), there are very few circumstances in which the optimization
    will not work.</p>

    <p>To explain how it works, we will go through this code</p>

  <div class="example"><pre>
Bin0 = &lt;&lt;0&gt;&gt;,                    %% 1
Bin1 = &lt;&lt;Bin0/binary,1,2,3&gt;&gt;,    %% 2
Bin2 = &lt;&lt;Bin1/binary,4,5,6&gt;&gt;,    %% 3
Bin3 = &lt;&lt;Bin2/binary,7,8,9&gt;&gt;,    %% 4
Bin4 = &lt;&lt;Bin1/binary,17&gt;&gt;,       %% 5 !!!
{Bin4,Bin3}                      %% 6</pre></div>

    <p>line by line.</p>

    <p>The first line (marked with the <span class="code">%% 1</span> comment), assigns
    a <span class="bold_code"><a href="#heap_binary">heap binary</a></span> to
    the variable <span class="code">Bin0</span>.</p>

    <p>The second line is an append operation. Since <span class="code">Bin0</span>
    has not been involved in an append operation,
    a new <span class="bold_code"><a href="#refc_binary">refc binary</a></span>
    will be created and the contents of <span class="code">Bin0</span> will be copied
    into it. The <strong>ProcBin</strong> part of the refc binary will have
    its size set to the size of the data stored in the binary, while
    the binary object will have extra space allocated. 
    The size of the binary object will be either twice the
    size of <span class="code">Bin0</span> or 256, whichever is larger. In this case
    it will be 256.</p>

    <p>It gets more interesting in the third line.
    <span class="code">Bin1</span> <strong>has</strong> been used in an append operation,
    and it has 255 bytes of unused storage at the end, so the three new bytes
    will be stored there.</p>

    <p>Same thing in the fourth line. There are 252 bytes left,
    so there is no problem storing another three bytes.</p>

    <p>But in the fifth line something <strong>interesting</strong> happens.
    Note that we don't append to the previous result in <span class="code">Bin3</span>,
    but to <span class="code">Bin1</span>. We expect that <span class="code">Bin4</span> will be assigned
    the value <span class="code">&lt;&lt;0,1,2,3,17&gt;&gt;</span>. We also expect that
    <span class="code">Bin3</span> will retain its value
    (<span class="code">&lt;&lt;0,1,2,3,4,5,6,7,8,9&gt;&gt;</span>).
    Clearly, the run-time system cannot write the byte <span class="code">17</span> into the binary,
    because that would change the value of <span class="code">Bin3</span> to
    <span class="code">&lt;&lt;0,1,2,3,4,17,6,7,8,9&gt;&gt;</span>.</p>

    <p>What will happen?</p>

    <p>The run-time system will see that <span class="code">Bin1</span> is the result
    from a previous append operation (not from the latest append operation),
    so it will <strong>copy</strong> the contents of <span class="code">Bin1</span> to a new binary
    and reserve extra storage and so on. (We will not explain here how the
    run-time system can know that it is not allowed to write into <span class="code">Bin1</span>;
    it is left as an exercise to the curious reader to figure out how it is
    done by reading the emulator sources, primarily <span class="code">erl_bits.c</span>.)</p>

    <h4>Circumstances that force copying</h4>
      

      <p>The optimization of the binary append operation requires that
      there is a <strong>single</strong> ProcBin and a <strong>single reference</strong> to the
      ProcBin for the binary. The reason is that the binary object can be
      moved (reallocated) during an append operation, and when that happens
      the pointer in the ProcBin must be updated. If there would be more than
      one ProcBin pointing to the binary object, it would not be possible to
      find and update all of them.</p>

      <p>Therefore, certain operations on a binary will mark it so that
      any future append operation will be forced to copy the binary.
      In most cases, the binary object will be shrunk at the same time 
      to reclaim the extra space allocated for growing.</p>

      <p>When appending to a binary</p>
      
  <div class="example"><pre>
Bin = &lt;&lt;Bin0,...&gt;&gt;</pre></div>

      <p>only the binary returned from the latest append operation will
      support further cheap append operations. In the code fragment above,
      appending to <span class="code">Bin</span> will be cheap, while appending to <span class="code">Bin0</span>
      will force the creation of a new binary and copying of the contents
      of <span class="code">Bin0</span>.</p>

      <p>If a binary is sent as a message to a process or port, the binary
      will be shrunk and any further append operation will copy the binary
      data into a new binary. For instance, in the following code fragment</p>

  <div class="example"><pre>
Bin1 = &lt;&lt;Bin0,...&gt;&gt;,
PortOrPid ! Bin1,
Bin = &lt;&lt;Bin1,...&gt;&gt;  %% Bin1 will be COPIED
</pre></div>

      <p><span class="code">Bin1</span> will be copied in the third line.</p>

      <p>The same thing happens if you insert a binary into an <strong>ets</strong>
      table or send it to a port using <span class="code">erlang:port_command/2</span>.</p>

      <p>Matching a binary will also cause it to shrink and the next append
      operation will copy the binary data:</p>

  <div class="example"><pre>
Bin1 = &lt;&lt;Bin0,...&gt;&gt;,
&lt;&lt;X,Y,Z,T/binary&gt;&gt; = Bin1,
Bin = &lt;&lt;Bin1,...&gt;&gt;  %% Bin1 will be COPIED
</pre></div>

      <p>The reason is that a <span class="bold_code"><a href="#match_context">match context</a></span>
      contains a direct pointer to the binary data.</p>

      <p>If a process simply keeps binaries (either in "loop data" or in the process
      dictionary), the garbage collector may eventually shrink the binaries.
      If only one such binary is kept, it will not be shrunk. If the process later
      appends to a binary that has been shrunk, the binary object will be reallocated
      to make place for the data to be appended.</p>
    

  

  <h3><a name="id63610">4.3 
        Matching binaries</a></h3>
    

    <p>We will revisit the example shown earlier</p>

  <p><strong>DO</strong> (in R12B)</p>
  <div class="example"><pre>
my_binary_to_list(&lt;&lt;H,T/binary&gt;&gt;) -&gt;
    [H|my_binary_to_list(T)];
my_binary_to_list(&lt;&lt;&gt;&gt;) -&gt; [].</pre></div>  

  <p>too see what is happening under the hood.</p>

  <p>The very first time <span class="code">my_binary_to_list/1</span> is called,
  a <span class="bold_code"><a href="#match_context">match context</a></span>
  will be created. The match context will point to the first
  byte of the binary. One byte will be matched out and the match context
  will be updated to point to the second byte in the binary.</p>

  <p>In R11B, at this point a <span class="bold_code"><a href="#sub_binary">sub binary</a></span>
  would be created. In R12B,
  the compiler sees that there is no point in creating a sub binary,
  because there will soon be a call to a function (in this case,
  to <span class="code">my_binary_to_list/1</span> itself) that will immediately
  create a new match context and discard the sub binary.</p>

  <p>Therefore, in R12B, <span class="code">my_binary_to_list/1</span> will call itself
  with the match context instead of with a sub binary. The instruction
  that initializes the matching operation will basically do nothing
  when it sees that it was passed a match context instead of a binary.</p>

  <p>When the end of the binary is reached and the second clause matches,
  the match context will simply be discarded (removed in the next
  garbage collection, since there is no longer any reference to it).</p>

  <p>To summarize, <span class="code">my_binary_to_list/1</span> in R12B only needs to create
  <strong>one</strong> match context and no sub binaries. In R11B, if the binary
  contains <strong>N</strong> bytes, <strong>N+1</strong> match contexts and <strong>N</strong>
  sub binaries will be created.</p>

  <p>In R11B, the fastest way to match binaries is:</p>

  <p><strong>DO NOT</strong> (in R12B)</p>
  <div class="example"><pre>
my_complicated_binary_to_list(Bin) -&gt;
    my_complicated_binary_to_list(Bin, 0).

my_complicated_binary_to_list(Bin, Skip) -&gt;
    case Bin of
	&lt;&lt;_:Skip/binary,Byte,_/binary&gt;&gt; -&gt;
	    [Byte|my_complicated_binary_to_list(Bin, Skip+1)];
	&lt;&lt;_:Skip/binary&gt;&gt; -&gt;
	    []
    end.</pre></div>

  <p>This function cleverly avoids building sub binaries, but it cannot
  avoid building a match context in each recursion step. Therefore, in both R11B and R12B,
  <span class="code">my_complicated_binary_to_list/1</span> builds <strong>N+1</strong> match
  contexts. (In a future release, the compiler might be able to generate code
  that reuses the match context, but don't hold your breath.)</p>

  <p>Returning to <span class="code">my_binary_to_list/1</span>, note that the match context was
  discarded when the entire binary had been traversed. What happens if
  the iteration stops before it has reached the end of the binary? Will
  the optimization still work?</p>

  <div class="example"><pre>
after_zero(&lt;&lt;0,T/binary&gt;&gt;) -&gt;
    T;
after_zero(&lt;&lt;_,T/binary&gt;&gt;) -&gt;
    after_zero(T);
after_zero(&lt;&lt;&gt;&gt;) -&gt;
    &lt;&lt;&gt;&gt;.
  </pre></div>

  <p>Yes, it will. The compiler will remove the building of the sub binary in the
  second clause</p>

  <div class="example"><pre>
.
.
.
after_zero(&lt;&lt;_,T/binary&gt;&gt;) -&gt;
    after_zero(T);
.
.
.</pre></div>

  <p>but will generate code that builds a sub binary in the first clause</p>

  <div class="example"><pre>
after_zero(&lt;&lt;0,T/binary&gt;&gt;) -&gt;
    T;
.
.
.</pre></div>

  <p>Therefore, <span class="code">after_zero/1</span> will build one match context and one sub binary
  (assuming it is passed a binary that contains a zero byte).</p>

  <p>Code like the following will also be optimized:</p>

  <div class="example"><pre>
all_but_zeroes_to_list(Buffer, Acc, 0) -&gt;
    {lists:reverse(Acc),Buffer};
all_but_zeroes_to_list(&lt;&lt;0,T/binary&gt;&gt;, Acc, Remaining) -&gt;
    all_but_zeroes_to_list(T, Acc, Remaining-1);
all_but_zeroes_to_list(&lt;&lt;Byte,T/binary&gt;&gt;, Acc, Remaining) -&gt;
    all_but_zeroes_to_list(T, [Byte|Acc], Remaining-1).</pre></div>

  <p>The compiler will remove building of sub binaries in the second and third clauses,
  and it will add an instruction to the first clause that will convert <span class="code">Buffer</span>
  from a match context to a sub binary (or do nothing if <span class="code">Buffer</span> already is a binary).</p>

  <p>Before you begin to think that the compiler can optimize any binary patterns,
  here is a function that the compiler (currently, at least) is not able to optimize:</p>

  <div class="example"><pre>
non_opt_eq([H|T1], &lt;&lt;H,T2/binary&gt;&gt;) -&gt;
    non_opt_eq(T1, T2);
non_opt_eq([_|_], &lt;&lt;_,_/binary&gt;&gt;) -&gt;
    false;
non_opt_eq([], &lt;&lt;&gt;&gt;) -&gt;
    true.</pre></div>

  <p>It was briefly mentioned earlier that the compiler can only delay creation of
  sub binaries if it can be sure that the binary will not be shared. In this case,
  the compiler cannot be sure.</p>

  <p>We will soon show how to rewrite <span class="code">non_opt_eq/2</span> so that the delayed sub binary
  optimization can be applied, and more importantly, we will show how you can find out
  whether your code can be optimized.</p>

  <h4>The bin_opt_info option</h4>
    

    <p>Use the <span class="code">bin_opt_info</span> option to have the compiler print a lot of 
    information about binary optimizations. It can be given either to the compiler or
    <span class="code">erlc</span></p>

  <div class="example"><pre>
erlc +bin_opt_info Mod.erl</pre></div>

    <p>or passed via an environment variable</p>

  <div class="example"><pre>
export ERL_COMPILER_OPTIONS=bin_opt_info</pre></div>

    <p>Note that the <span class="code">bin_opt_info</span> is not meant to be a permanent option added
    to your <span class="code">Makefile</span>s, because it is not possible to eliminate all messages that
    it generates. Therefore, passing the option through the environment is in most cases
    the most practical approach.</p>

    <p>The warnings will look like this:</p>

  <div class="example"><pre>
./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: sub binary is used or returned
./efficiency_guide.erl:62: Warning: OPTIMIZED: creation of sub binary delayed</pre></div>

    <p>To make it clearer exactly what code the warnings refer to,
    in the examples that follow, the warnings are inserted as comments
    after the clause they refer to:</p>

  <div class="example"><pre>
after_zero(&lt;&lt;0,T/binary&gt;&gt;) -&gt;
         %% NOT OPTIMIZED: sub binary is used or returned
    T;
after_zero(&lt;&lt;_,T/binary&gt;&gt;) -&gt;
         %% OPTIMIZED: creation of sub binary delayed
    after_zero(T);
after_zero(&lt;&lt;&gt;&gt;) -&gt;
    &lt;&lt;&gt;&gt;.</pre></div>

    <p>The warning for the first clause tells us that it is not possible to
    delay the creation of a sub binary, because it will be returned.
    The warning for the second clause tells us that a sub binary will not be
    created (yet).</p>

    <p>It is time to revisit the earlier example of the code that could not
    be optimized and find out why:</p>

  <div class="example"><pre>
non_opt_eq([H|T1], &lt;&lt;H,T2/binary&gt;&gt;) -&gt;
        %% INFO: matching anything else but a plain variable to
	%%    the left of binary pattern will prevent delayed 
	%%    sub binary optimization;
	%%    SUGGEST changing argument order
        %% NOT OPTIMIZED: called function non_opt_eq/2 does not
	%%    begin with a suitable binary matching instruction
    non_opt_eq(T1, T2);
non_opt_eq([_|_], &lt;&lt;_,_/binary&gt;&gt;) -&gt;
    false;
non_opt_eq([], &lt;&lt;&gt;&gt;) -&gt;
    true.</pre></div>

    <p>The compiler emitted two warnings. The <span class="code">INFO</span> warning refers to the function
    <span class="code">non_opt_eq/2</span> as a callee, indicating that any functions that call <span class="code">non_opt_eq/2</span>
    will not be able to make delayed sub binary optimization.
    There is also a suggestion to change argument order.
    The second warning (that happens to refer to the same line) refers to the construction of
    the sub binary itself.</p>
    
    <p>We will soon show another example that should make the distinction between <span class="code">INFO</span>
    and <span class="code">NOT OPTIMIZED</span> warnings somewhat clearer, but first we will heed the suggestion
    to change argument order:</p>

  <div class="example"><pre>
opt_eq(&lt;&lt;H,T1/binary&gt;&gt;, [H|T2]) -&gt;
        %% OPTIMIZED: creation of sub binary delayed
    opt_eq(T1, T2);
opt_eq(&lt;&lt;_,_/binary&gt;&gt;, [_|_]) -&gt;
    false;
opt_eq(&lt;&lt;&gt;&gt;, []) -&gt;
    true.</pre></div>

    <p>The compiler gives a warning for the following code fragment:</p>

  <div class="example"><pre>
match_body([0|_], &lt;&lt;H,_/binary&gt;&gt;) -&gt;
        %% INFO: matching anything else but a plain variable to
	%%    the left of binary pattern will prevent delayed 
	%%    sub binary optimization;
	%%    SUGGEST changing argument order
    done;
.
.
.</pre></div>

    <p>The warning means that <strong>if</strong> there is a call to <span class="code">match_body/2</span>
    (from another clause in <span class="code">match_body/2</span> or another function), the
    delayed sub binary optimization will not be possible. There will be additional
    warnings for any place where a sub binary is matched out at the end of and
    passed as the second argument to <span class="code">match_body/2</span>. For instance:</p>

  <div class="example"><pre>
match_head(List, &lt;&lt;_:10,Data/binary&gt;&gt;) -&gt;
        %% NOT OPTIMIZED: called function match_body/2 does not
	%%     begin with a suitable binary matching instruction
    match_body(List, Data).</pre></div>

  

  <h4>Unused variables</h4>
    

    <p>The compiler itself figures out if a variable is unused. The same
    code is generated for each of the following functions</p>

  <div class="example"><pre>
count1(&lt;&lt;_,T/binary&gt;&gt;, Count) -&gt; count1(T, Count+1);
count1(&lt;&lt;&gt;&gt;, Count) -&gt; Count.

count2(&lt;&lt;H,T/binary&gt;&gt;, Count) -&gt; count2(T, Count+1);
count2(&lt;&lt;&gt;&gt;, Count) -&gt; Count.

count3(&lt;&lt;_H,T/binary&gt;&gt;, Count) -&gt; count3(T, Count+1);
count3(&lt;&lt;&gt;&gt;, Count) -&gt; Count.</pre></div>

  <p>In each iteration, the first 8 bits in the binary will be skipped, not matched out.</p>

  

  

</div>
<div class="footer">
<hr>
<p>Copyright © 2001-2012 Ericsson AB. All Rights Reserved.</p>
</div>
</div>
</div></body>
</html>