summaryrefslogtreecommitdiff
path: root/docs/PTHInternals.rst
blob: 7401cf9b4d4bdaa221dddd60c4c5941a1fd4d779 (plain)
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
==========================
Pretokenized Headers (PTH)
==========================

This document first describes the low-level interface for using PTH and
then briefly elaborates on its design and implementation. If you are
interested in the end-user view, please see the :ref:`User's Manual
<usersmanual-precompiled-headers>`.

Using Pretokenized Headers with ``clang`` (Low-level Interface)
===============================================================

The Clang compiler frontend, ``clang -cc1``, supports three command line
options for generating and using PTH files.

To generate PTH files using ``clang -cc1``, use the option ``-emit-pth``:

.. code-block:: console

  $ clang -cc1 test.h -emit-pth -o test.h.pth

This option is transparently used by ``clang`` when generating PTH
files. Similarly, PTH files can be used as prefix headers using the
``-include-pth`` option:

.. code-block:: console

  $ clang -cc1 -include-pth test.h.pth test.c -o test.s

Alternatively, Clang's PTH files can be used as a raw "token-cache" (or
"content" cache) of the source included by the original header file.
This means that the contents of the PTH file are searched as substitutes
for *any* source files that are used by ``clang -cc1`` to process a
source file. This is done by specifying the ``-token-cache`` option:

.. code-block:: console

  $ cat test.h
  #include <stdio.h>
  $ clang -cc1 -emit-pth test.h -o test.h.pth
  $ cat test.c
  #include "test.h"
  $ clang -cc1 test.c -o test -token-cache test.h.pth

In this example the contents of ``stdio.h`` (and the files it includes)
will be retrieved from ``test.h.pth``, as the PTH file is being used in
this case as a raw cache of the contents of ``test.h``. This is a
low-level interface used to both implement the high-level PTH interface
as well as to provide alternative means to use PTH-style caching.

PTH Design and Implementation
=============================

Unlike GCC's precompiled headers, which cache the full ASTs and
preprocessor state of a header file, Clang's pretokenized header files
mainly cache the raw lexer *tokens* that are needed to segment the
stream of characters in a source file into keywords, identifiers, and
operators. Consequently, PTH serves to mainly directly speed up the
lexing and preprocessing of a source file, while parsing and
type-checking must be completely redone every time a PTH file is used.

Basic Design Tradeoffs
----------------------

In the long term there are plans to provide an alternate PCH
implementation for Clang that also caches the work for parsing and type
checking the contents of header files. The current implementation of PCH
in Clang as pretokenized header files was motivated by the following
factors:

**Language independence**
   PTH files work with any language that
   Clang's lexer can handle, including C, Objective-C, and (in the early
   stages) C++. This means development on language features at the
   parsing level or above (which is basically almost all interesting
   pieces) does not require PTH to be modified.

**Simple design**
   Relatively speaking, PTH has a simple design and
   implementation, making it easy to test. Further, because the
   machinery for PTH resides at the lower-levels of the Clang library
   stack it is fairly straightforward to profile and optimize.

Further, compared to GCC's PCH implementation (which is the dominate
precompiled header file implementation that Clang can be directly
compared against) the PTH design in Clang yields several attractive
features:

**Architecture independence**
   In contrast to GCC's PCH files (and
   those of several other compilers), Clang's PTH files are architecture
   independent, requiring only a single PTH file when building a
   program for multiple architectures.

   For example, on Mac OS X one may wish to compile a "universal binary"
   that runs on PowerPC, 32-bit Intel (i386), and 64-bit Intel
   architectures. In contrast, GCC requires a PCH file for each
   architecture, as the definitions of types in the AST are
   architecture-specific. Since a Clang PTH file essentially represents
   a lexical cache of header files, a single PTH file can be safely used
   when compiling for multiple architectures. This can also reduce
   compile times because only a single PTH file needs to be generated
   during a build instead of several.

**Reduced memory pressure**
   Similar to GCC, Clang reads PTH files
   via the use of memory mapping (i.e., ``mmap``). Clang, however,
   memory maps PTH files as read-only, meaning that multiple invocations
   of ``clang -cc1`` can share the same pages in memory from a
   memory-mapped PTH file. In comparison, GCC also memory maps its PCH
   files but also modifies those pages in memory, incurring the
   copy-on-write costs. The read-only nature of PTH can greatly reduce
   memory pressure for builds involving multiple cores, thus improving
   overall scalability.

**Fast generation**
   PTH files can be generated in a small fraction
   of the time needed to generate GCC's PCH files. Since PTH/PCH
   generation is a serial operation that typically blocks progress
   during a build, faster generation time leads to improved processor
   utilization with parallel builds on multicore machines.

Despite these strengths, PTH's simple design suffers some algorithmic
handicaps compared to other PCH strategies such as those used by GCC.
While PTH can greatly speed up the processing time of a header file, the
amount of work required to process a header file is still roughly linear
in the size of the header file. In contrast, the amount of work done by
GCC to process a precompiled header is (theoretically) constant (the
ASTs for the header are literally memory mapped into the compiler). This
means that only the pieces of the header file that are referenced by the
source file including the header are the only ones the compiler needs to
process during actual compilation. While GCC's particular implementation
of PCH mitigates some of these algorithmic strengths via the use of
copy-on-write pages, the approach itself can fundamentally dominate at
an algorithmic level, especially when one considers header files of
arbitrary size.

There is also a PCH implementation for Clang based on the lazy
deserialization of ASTs. This approach theoretically has the same
constant-time algorithmic advantages just mentioned but also retains some
of the strengths of PTH such as reduced memory pressure (ideal for
multi-core builds).

Internal PTH Optimizations
--------------------------

While the main optimization employed by PTH is to reduce lexing time of
header files by caching pre-lexed tokens, PTH also employs several other
optimizations to speed up the processing of header files:

-  ``stat`` caching: PTH files cache information obtained via calls to
   ``stat`` that ``clang -cc1`` uses to resolve which files are included
   by ``#include`` directives. This greatly reduces the overhead
   involved in context-switching to the kernel to resolve included
   files.

-  Fast skipping of ``#ifdef`` ... ``#endif`` chains: PTH files
   record the basic structure of nested preprocessor blocks. When the
   condition of the preprocessor block is false, all of its tokens are
   immediately skipped instead of requiring them to be handled by
   Clang's preprocessor.