Skip to content

Commit

Permalink
deploy: 0f8ea69
Browse files Browse the repository at this point in the history
  • Loading branch information
avsm committed Nov 23, 2022
1 parent b75dc89 commit 344a08d
Show file tree
Hide file tree
Showing 25 changed files with 207 additions and 207 deletions.
6 changes: 3 additions & 3 deletions command-line-parsing.html
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,11 @@ <h3>Installing the Completion Fragment</h3>
add diff help version</code></pre>
</div>
<p>Command completion support works for flags and grouped commands and is very useful when building larger command-line interfaces. Don’t forget to install the shell fragment into your global <em class="filename">bash_completion.d</em> directory if you want it to be loaded in all of your login shells. <a data-primary="completion handlers" data-type="indexterm">&nbsp;</a></p>
<div data-type="note">
<h4 id="installing-a-generic-completion-handler">Installing a Generic Completion Handler</h4>
<section data-type="note" class="level4" id="installing-a-generic-completion-handler">
<h4>Installing a Generic Completion Handler</h4>
<p>Sadly, <code>bash</code> doesn’t support installing a generic handler for all Command-based applications. This means you have to install the completion script for every application, but you should be able to automate this in the build and packaging system for your application.</p>
<p>It will help to check out how other applications install tab-completion scripts and follow their lead, as the details are very OS-specific.</p>
</div>
</section>
</section>
</section>
<section class="level2" id="alternative-command-line-parsers">
Expand Down
24 changes: 12 additions & 12 deletions compiler-backend.html
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,12 @@ <h2>Generating Portable Bytecode</h2>
</div>
<p>The preceding bytecode has been simplified from the lambda form into a set of simple instructions that are executed serially by the interpreter.</p>
<p>There are around 140 instructions in total, but most are just minor variants of commonly encountered operations (e.g., function application at a specific arity). You can find full details <a href="http://cadmium.x9c.fr/distrib/caml-instructions.pdf">online</a>. <a data-secondary="instruction set for" data-primary="bytecode compiler" data-type="indexterm">&nbsp;</a></p>
<div data-type="note">
<h4 id="where-did-the-bytecode-instruction-set-come-from">Where Did the Bytecode Instruction Set Come From?</h4>
<section data-type="note" class="level4" id="where-did-the-bytecode-instruction-set-come-from">
<h4>Where Did the Bytecode Instruction Set Come From?</h4>
<p>The bytecode interpreter is much slower than compiled native code, but is still remarkably performant for an interpreter without a JIT compiler. Its efficiency can be traced back to Xavier Leroy’s ground-breaking work in 1990, <a href="http://hal.inria.fr/docs/00/07/00/49/PS/RT-0117.ps">“The ZINC experiment: An Economical Implementation of the ML Language”.</a></p>
<p>This paper laid the theoretical basis for the implementation of an instruction set for a strictly evaluated functional language such as OCaml. The bytecode interpreter in modern OCaml is still based on the ZINC model. The native code compiler uses a different model since it uses CPU registers for function calls instead of always passing arguments on the stack, as the bytecode interpreter does.</p>
<p>Understanding the reasoning behind the different implementations of the bytecode interpreter and the native compiler is a very useful exercise for any budding language hacker.</p>
</div>
</section>
<section class="level3" id="compiling-and-linking-bytecode">
<h3>Compiling and Linking Bytecode</h3>
<p>The <code>ocamlc</code> command compiles individual <code>ml</code> files into bytecode files that have a <code>cmo</code> extension. The compiled bytecode files are matched with the associated <code>cmi</code> interface, which contains the type signature exported to other compilation units. <a data-secondary="compiling and linking code" data-primary="bytecode compiler" data-type="indexterm">&nbsp;</a></p>
Expand Down Expand Up @@ -439,10 +439,10 @@ <h4>Benchmarking Polymorphic Comparison</h4>
</code></pre>
</div>
<p>We see that the polymorphic comparison is close to 10 times slower! These results shouldn’t be taken too seriously, as this is a very narrow test that, like all such microbenchmarks, isn’t representative of more complex codebases. However, if you’re building numerical code that runs many iterations in a tight inner loop, it’s worth manually peering at the produced assembly code to see if you can hand-optimize it.</p>
<div data-type="note">
<h4 id="accessing-stdlib-modules-from-within-core">Accessing Stdlib Modules from Within Core</h4>
</section>
<section data-type="note" class="level4" id="accessing-stdlib-modules-from-within-core">
<h4>Accessing Stdlib Modules from Within Core</h4>
<p>In the benchmark above comparing polymorphic and monomorphic comparison, you may have noticed that we prepended the comparison functions with <code>Stdlib</code>. This is because the Core module explicitly redefines the <code>&gt;</code> and <code>&lt;</code> and <code>=</code> operators to be specialized for operating over <code>int</code> types, as explained in <a data-type="xref" href="maps-and-hashtables.html#the-polymorphic-comparator">Chapter 14, Maps and Hashtables</a>. You can always recover any of the OCaml standard library functions by accessing them through the <code>Stdlib</code> module, as we did in our benchmark.</p>
</div>
</section>
</section>
<section class="level3" id="debugging-native-code-binaries">
Expand Down Expand Up @@ -607,16 +607,16 @@ <h4>Perf</h4>
</div>
<p>This trace broadly reflects the results of the benchmark itself. The mutable benchmark consists of the combination of the call to <code>test_mutable</code> and the <code>caml_modify</code> write barrier function in the runtime. This adds up to slightly over half the execution time of the application.</p>
<p>Perf has a growing collection of other commands that let you archive these runs and compare them against each other. You can read more on the <a href="http://perf.wiki.kernel.org">home page</a>. <a data-primary="frame pointers" data-type="indexterm">&nbsp;</a></p>
<div data-type="note">
<h4 id="using-the-frame-pointer-to-get-more-accurate-traces">Using the Frame Pointer to Get More Accurate Traces</h4>
</section>
<section data-type="note" class="level4" id="using-the-frame-pointer-to-get-more-accurate-traces">
<h4>Using the Frame Pointer to Get More Accurate Traces</h4>
<p>Although Perf doesn’t require adding in explicit probes to the binary, it does need to understand how to unwind function calls so that the kernel can accurately record the function backtrace for every event. Since Linux 3.9 the kernel has had support for using DWARF debug information to parse the program stack, which is emitted when the <code>-g</code> flag is passed to the OCaml compiler. For even more accurate stack parsing, we need the compiler to fall back to using the same conventions as C for function calls. On 64-bit Intel systems, this means that a special register known as the <em>frame pointer</em> is used to record function call history. Using the frame pointer in this fashion means a slowdown (typically around 3-5%) since it’s no longer available for general-purpose use.</p>
<p>OCaml thus makes the frame pointer an optional feature that can be used to improve the resolution of Perf traces. opam provides a compiler switch that compiles OCaml with the frame pointer activated:</p>
<div class="highlight">
<pre data-filter-output=">" data-host="lama" data-user="fun" class="command-line"><code class="language-bash">opam switch create 4.13+fp ocaml-variants.4.13.1+options ocaml-option-fp
</code></pre>
</div>
<p>Using the frame pointer changes the OCaml calling convention, but opam takes care of recompiling all your libraries with the new interface.</p>
</div>
</section>
</section>
<section class="level3" id="embedding-native-code-in-c">
Expand All @@ -635,11 +635,11 @@ <h3>Embedding Native Code in C</h3>
After calling OCaml</code></pre>
</div>
<p>The <code>embed_native.o</code> is a standalone object file that has no further references to OCaml code beyond the runtime library, just as with the bytecode runtime. Do remember that the link order of the libraries is significant in modern GNU toolchains (especially as used in Ubuntu 11.10 and later) that resolve symbols from left to right in a single pass.<a data-secondary="activating debug runtime" data-primary="debugging" data-type="indexterm">&nbsp;</a></p>
<div data-type="note">
<h4 id="activating-the-debug-runtime">Activating the Debug Runtime</h4>
<section data-type="note" class="level4" id="activating-the-debug-runtime">
<h4>Activating the Debug Runtime</h4>
<p>Despite your best efforts, it is easy to introduce a bug into some components, such as C bindings, that causes heap invariants to be violated. OCaml includes a <code>libasmrund.a</code> variant of the runtime library which is compiled with extra debugging checks that perform extra memory integrity checks during every garbage collection cycle. Running these extra checks will abort the program nearer the point of corruption and help isolate the bug in the C code.</p>
<p>To use the debug library, just link your program with the <code>-runtime-variant d</code> flag:</p>
</div>
</section>
<div class="highlight">
<pre data-filter-output=">" data-host="lama" data-user="fun" class="command-line"><code class="language-bash">ocamlopt -runtime-variant d -verbose -o hello.native hello.ml
&gt;+ as -o 'hello.o' '/tmp/build_cd0b96_dune/camlasmd3c336.s'
Expand Down
12 changes: 6 additions & 6 deletions compiler-frontend.html
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,13 @@ <h3>Displaying Inferred Types from the Compiler</h3>
&gt; Actual declaration
[2]</code></pre>
</div>
<div data-type="note" class="allow_break">
<h4 id="which-comes-first-the-ml-or-the-mli">Which Comes First: The ml or the mli?</h4>
<section data-type="note" class="level4 allow_break" id="which-comes-first-the-ml-or-the-mli">
<h4>Which Comes First: The ml or the mli?</h4>
<p>There are two schools of thought on which order OCaml code should be written in. It’s very easy to begin writing code by starting with an <code>ml</code> file and using the type inference to guide you as you build up your functions. The <code>mli</code> file can then be generated as described, and the exported functions documented. <a data-primary="mli files" data-type="indexterm">&nbsp;</a><a data-secondary="mli files" data-primary="files" data-type="indexterm">&nbsp;</a><a data-primary="ml files" data-type="indexterm">&nbsp;</a><a data-secondary="ml files" data-primary="files" data-type="indexterm">&nbsp;</a></p>
<p>If you’re writing code that spans multiple files, it’s sometimes easier to start by writing all the <code>mli</code> signatures and checking that they type-check against one another. Once the signatures are in place, you can write the implementations with the confidence that they’ll all glue together correctly, with no cyclic dependencies among the modules.</p>
<p>As with any such stylistic debate, you should experiment with which system works best for you. Everyone agrees on one thing though: no matter in what order you write them, production code should always explicitly define an <code>mli</code> file for every <code>ml</code> file in the project. It’s also perfectly fine to have an <code>mli</code> file without a corresponding <code>ml</code> file if you’re only declaring signatures (such as module types).</p>
<p>Signature files provide a place to write succinct documentation and to abstract internal details that shouldn’t be exported. Maintaining separate signature files also speeds up incremental compilation in larger code bases, since recompiling a <code>mli</code> signature is much faster than a full compilation of the implementation to native code.</p>
</div>
</section>
</section>
<section class="level3" id="type-inference-1">
<h3>Type Inference</h3>
Expand Down Expand Up @@ -517,8 +517,9 @@ <h4>Defining a Module Search Path</h4>
<p>The type checker resolves such module references into concrete structures and signatures in order to unify types across module boundaries. It does this by searching a list of directories for a compiled interface file matching that module’s name. For example, it will look for <code>alice.cmi</code> and <code>bob.cmi</code> on the search path and use the first ones it encounters as the interfaces for <code>Alice</code> and <code>Bob</code>.</p>
<p>The module search path is set by adding <code>-I</code> flags to the compiler command line with the directory containing the <code>cmi</code> files as the argument. Manually specifying these flags gets complex when you have lots of libraries, and is the reason why tools like <code>dune</code> and <code>ocamlfind</code> exist. They both automate the process of turning third-party package names and build descriptions into command-line flags that are passed to the compiler command line.</p>
<p>By default, only the current directory and the OCaml standard library will be searched for <code>cmi</code> files. The <code>Stdlib</code> module from the standard library will also be opened by default in every compilation unit. The standard library location is obtained by running <code>ocamlc -where</code> and can be overridden by setting the <code>CAMLLIB</code> environment variable. Needless to say, don’t override the default path unless you have a good reason to (such as setting up a cross-compilation environment). <a data-primary="cmi files" data-type="indexterm">&nbsp;</a><a data-secondary="cmi files" data-primary="files" data-type="indexterm">&nbsp;</a><a data-secondary="ocamlogjinfo" data-primary="OCaml toolchain" data-type="indexterm">&nbsp;</a></p>
<div data-type="note">
<h4 id="inspecting-compilation-units-with-ocamlobjinfo">Inspecting Compilation Units with ocamlobjinfo</h4>
</section>
<section data-type="note" class="level4" id="inspecting-compilation-units-with-ocamlobjinfo">
<h4>Inspecting Compilation Units with ocamlobjinfo</h4>
<p>For separate compilation to be sound, we need to ensure that all the <code>cmi</code> files used to type-check a module are the same across compilation runs. If they vary, this raises the possibility of two modules checking different type signatures for a common module with the same name. This in turn lets the program completely violate the static type system and can lead to memory corruption and crashes.</p>
<p>OCaml guards against this by recording a MD5 checksum in every <code>cmi</code>. Let’s examine our earlier <code>typedef.ml</code> more closely:</p>
<div class="highlight">
Expand All @@ -542,7 +543,6 @@ <h4 id="inspecting-compilation-units-with-ocamlobjinfo">Inspecting Compilation U
over interface Map</code></pre>
</div>
<p>This hash check is very conservative, but ensures that separate compilation remains type-safe all the way up to the final link phase. Your build system should ensure that you never see the preceding error messages, but if you do run into it, just clean out your intermediate files and recompile from scratch.</p>
</div>
</section>
</section>
<section class="level3" id="wrapping-libraries-with-module-aliases">
Expand Down
Loading

0 comments on commit 344a08d

Please sign in to comment.