From 23ea4a5db0a6e1437cdc2236f4a69f56aafab545 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Mon, 6 Apr 2026 20:38:34 +0100 Subject: [PATCH 01/21] Frame pointers frame pointers frame pointers --- peps/pep-0830.rst | 1030 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1030 insertions(+) create mode 100644 peps/pep-0830.rst diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst new file mode 100644 index 00000000000..4d7f2b051ca --- /dev/null +++ b/peps/pep-0830.rst @@ -0,0 +1,1030 @@ +PEP: 830 +Title: Frame Pointers Everywhere: Enabling System-Level Observability for Python +Author: Pablo Galindo Salgado , + Ken Jin , + Savannah Ostrowski , + Diego Russo +Discussions-To: +Status: Draft +Type: Standards Track +Created: 14-Mar-2026 +Python-Version: 3.15 +Post-History: + + +Abstract +======== + +This PEP does two things: + +1. **Build CPython with frame pointers by default on platforms that support + them.** The default build configuration is changed to compile the + interpreter with ``-fno-omit-frame-pointer`` and + ``-mno-omit-leaf-frame-pointer``. The flags are added to ``CFLAGS``, so they + apply to the interpreter itself and propagate to C extension modules built + against this Python via ``sysconfig``. An opt-out ``configure`` flag + (``--without-frame-pointers``) is provided for deployments that require + maximum raw throughput. + +2. **Strongly recommend that all build systems in the Python ecosystem build + with frame pointers by default.** This PEP recommends that *every* compiled + component that participates in the Python call stack (C extensions, Rust + extensions, embedding applications, and native libraries) should enable + frame pointers. A frame-pointer chain is only as complete as its weakest + link: a single library without frame pointers breaks profiling, debugging, + and tracing for the entire process. + +Frame pointers are a CPU register convention that allows profilers, debuggers, +and system tracing tools to reconstruct the call stack of a running process +quickly and reliably. Omitting them (the compiler's default at ``-O1`` and +above) prevents these tools from producing useful call stacks for Python +processes, and undermines the perf trampoline support CPython shipped in 3.12. + +The measured overhead is under 2% geometric mean for typical workloads. +Multiple major Linux distributions, language runtimes, and Python ecosystem +tools have already adopted this change. No existing PEP covers this topic; +CPython issue `#96174`_ has been open since August 2022 without resolution. + + +Motivation +========== + +Python's observability story (profiling, debugging, and system-level tracing) +is fundamentally limited by the absence of frame pointers. The core motivation +of this PEP is to make Python observable by default: profilers faster and more +accurate, debuggers more reliable, and eBPF-based tools functional without +workarounds. + +Today, users who want to profile CPython with system tools must rebuild the +interpreter with special compiler flags, a step that most users cannot or will +not take. The Fedora 38 frame-pointer proposal [#fedora38]_ highlights this as +the key problem: without frame pointers in the default build, developers must +"recompile their program with sufficient debugging information" and "reproduce +the scenario under which the software performed poorly," which is often +impossible for production issues. Ubuntu 24.04's analysis [#ubuntu2404]_ makes +the same argument: frame pointers "allow bcc-tools, bpftrace, perf and other +such tooling to work out of the box." The goal of this PEP is to make that the +default experience for Python. + +The performance wins that profiling enables far outweigh the modest overhead of +frame pointers. As Brendan Gregg notes: "I've seen frame pointers help find +performance wins ranging from 5% to 500%" [#gregg2024]_. A 1-2% overhead that +unlocks the ability to find 5-500% improvements is a favourable trade. + +What Are Frame Pointers? +------------------------ + +When a program runs, each function call creates a **stack frame**, a block of +memory on the call stack that holds the function's local variables, its +arguments, and the address to return to when the function finishes. The **call +stack** is the chain of all active stack frames: it records which function +called which, all the way from ``main()`` to the function currently executing. + +A **frame pointer** is a CPU register (``%rbp`` on x86-64, ``x29`` on AArch64) +that each function sets to point to the base of its own stack frame. Each +frame also stores the *previous* frame pointer, creating a linked list through +the entire call stack:: + + ┌──────────────────┐ + │ main() │ ◄─── frame pointer chain + │ saved %rbp ─────┼──► (bottom of stack) + ├──────────────────┤ + │ PyRun_String() │ + │ saved %rbp ─────┼──► main's frame + ├──────────────────┤ + │ _PyEval_Eval…() │ + │ saved %rbp ─────┼──► PyRun_String's frame + ├──────────────────┤ + │ call_function() │ ◄─── current %rbp + │ saved %rbp ─────┼──► _PyEval_Eval's frame + └──────────────────┘ + +Stack unwinding is the process of walking this chain to reconstruct the call +stack. Profilers do it to find out where the program is spending time; +debuggers do it to show backtraces; crash handlers do it to produce useful +error reports. With frame pointers, unwinding is a simple pointer chase: read +``%rbp``, follow the link, repeat. It takes microseconds and requires no +external data. + +At optimisation levels ``-O1`` and above, GCC and Clang omit frame pointers by +default [#gcc_fomit]_. This frees the ``%rbp`` register for general use, +giving the optimiser one more register to work with. On x86-64 this is a gain +of one register out of 16 (about 7%). The performance benefit is small +(typically 1-2%) but it was considered worthwhile when the convention was +established for 32-bit x86, where the gain was one register out of 6 (~20%). + +Without frame pointers, the linked list does not exist. Tools that need to +walk the call stack must instead parse DWARF debug information (a complex, +variable-length encoding of how each function laid out its stack frame). This +is slower, more fragile, and impossible in some contexts (such as inside the +Linux kernel). In the worst case, tools simply produce broken or incomplete +results. + +Here is a concrete example. A ``perf`` profile of a Python process **without** +frame pointers typically shows:: + + 100.00% python libpython3.14.so _PyEval_EvalFrameDefault + | + ---_PyEval_EvalFrameDefault + (truncated, no further frames available) + +The same profile **with** frame pointers shows the full chain:: + + 100.00% python libpython3.14.so _PyEval_EvalFrameDefault + | + ---_PyEval_EvalFrameDefault + | + +--PyObject_Call + | PyRun_StringFlags + | PyRun_SimpleStringFlags + | Py_RunMain + | main + | + +--call_function + fast_function + ... + +The first trace is useless for diagnosing performance problems; the second +tells the developer exactly what code path is hot. + +Profilers Are Slower and Less Accurate Without Frame Pointers +------------------------------------------------------------- + +Statistical profilers (``perf``, py-spy, Austin, Pyroscope, Parca, and others) +work by periodically sampling the call stack of a running process. With frame +pointers, this sampling is a simple pointer chase: the profiler reads ``%rbp``, +follows the chain, and reconstructs the full call stack in microseconds. This +is fast enough to sample at 10,000 Hz in production with negligible overhead. + +Without frame pointers, the profiler must fall back to DWARF unwinding, a +method that parses compiler-generated debug metadata to reconstruct the call +chain. ``perf --call-graph dwarf`` copies 8 KB of raw stack per sample to +userspace, then parses ``.eh_frame`` debug sections offline to reconstruct each +frame. In a direct measurement on CPython 3.15-dev, profiling the same +workload at the same sampling rate produced a 5.6 MB ``perf.data`` file with +frame-pointer unwinding versus a 306.5 MB file with DWARF unwinding (**55x +larger**) for the same ~38,000 samples. + +DWARF mode also requires offline post-processing with ``perf report`` (which +itself can consume up to 17% of CPU [#redhat]_), silently truncates stacks +deeper than the copy window, and cannot be used at high sampling rates in +production. The result: profiling Python services in production requires +either accepting broken stacks or accepting orders-of-magnitude more overhead +and storage. + +To quantify the difference, we benchmarked the time to unwind a 64-frame call +stack on x86-64 Linux using frame-pointer walking (``%rbp`` chain chase, the +method used by the kernel's ``perf_events`` and ``bpf_get_stackid()``) and +three widely-used DWARF-based unwinders: libunwind [#libunwind]_, glibc's +``backtrace()``, and framehop [#framehop]_ (the Rust unwinder used by samply +[#samply]_). Each unwinder was tested against the same program compiled with +and without ``-fno-omit-frame-pointer``. + +Frame-pointer walking completed a 64-frame unwind in **116 ns**, on average +**210x faster** than the DWARF alternatives tested. Without frame pointers, the +frame-pointer walk recovers **zero usable frames** (the ``%rbp`` chain does not +exist), while the DWARF unwinders continue to function at essentially the same +cost. + +At a typical production sampling rate of 10,000 Hz, frame-pointer unwinding at +this depth consumes roughly **1.2 ms of CPU per second** (0.12%), while the +slowest DWARF unwinder tested consumes over **240 ms per second** (24%). +DWARF-based profiling works and is how most profilers operate today, but it +carries substantially higher overhead than frame-pointer unwinding. + +For BPF-based profilers (bpftrace, bcc's ``profile.py``, Pyroscope, Parca, +Elastic Universal Profiling), the situation is worse. The BPF helper +``bpf_get_stackid()``, the foundation of every eBPF profiler in production +today, walks the frame-pointer chain and has **no fallback to DWARF**. Without +frame pointers, these tools simply produce truncated or empty stacks for Python +processes. The Linux kernel has no DWARF unwinder and, per Linus Torvalds, +will not gain one [#torvalds_fp]_; the kernel developed its own ORC format for +internal use instead. + +The impact extends beyond CPU profiling. Off-CPU flame graphs (used to +diagnose latency caused by I/O waits, lock contention, and scheduling delays) +rely on the same ``bpf_get_stackid()`` helper to capture the stack at the point +where a thread blocks. As Brendan Gregg notes, off-CPU flame graphs "can be +dominated by libc read/write and mutex functions, so without frame pointers end +up mostly broken" [#gregg2024]_. For Python services where latency matters +more than raw CPU throughput, off-CPU profiling is often the most valuable +diagnostic tool, and it is completely non-functional without frame pointers. + +Debuggers Benefit from Frame Pointers +------------------------------------- + +Debuggers such as GDB and LLDB can unwind stacks without frame pointers. They +use multiple strategies: DWARF CFI metadata (``.debug_frame`` and ``.eh_frame`` +sections), assembly prologue analysis, compact unwind info (on macOS), and +various platform-specific heuristics. In typical interactive debugging +sessions with full debug info available, these mechanisms work well. + +Frame pointers nonetheless make debugging faster and more robust in several +important scenarios. + +Production deployments commonly strip debug symbols or ship without matching +``debuginfo`` packages. When DWARF metadata is unavailable, debuggers cannot +unwind past the gap. Frame pointers survive binary stripping and require no +side-channel data, allowing a backtrace to succeed where DWARF-based unwinding +cannot. This matters most for core dump analysis: when analysing a crash from +a production process, debuggers have one chance to reconstruct the stack, and +if debug packages are mismatched or absent for some shared objects, DWARF +unwinding stops at the first gap while frame pointers let the debugger continue +through it. + +CPython's JIT stencils and perf trampoline stubs contain no DWARF metadata. +Frame pointers are the only way for a debugger to unwind through these frames. + +Tools like pystack, which analyse core files and remote processes using +elfutils (libdw), can walk frame pointers without any additional metadata, but +without them they require debug symbols for every shared object in the process, +a condition rarely met in production containers. + +Frame-pointer unwinding is also substantially faster. As shown in the +benchmarks above, a frame-pointer walk completes a 64-frame unwind in 116 ns, +roughly 210x faster than the DWARF alternatives. For debugger operations that +unwind repeatedly (e.g. conditional breakpoints that evaluate at every hit), +this difference matters. + +The Kernel's Stack Unwinder Only Uses Frame Pointers +---------------------------------------------------- + +The Linux kernel provides two built-in mechanisms for capturing userspace call +stacks: the ``perf_events`` subsystem and the eBPF helper functions. Both use +the **same kernel-side frame-pointer unwinder** and neither has any fallback to +DWARF. + +``perf_events`` is the kernel subsystem behind ``perf record``. When ``perf`` +is configured with ``--call-graph fp`` (frame pointer), the kernel walks the +userspace frame-pointer chain directly from the interrupt handler that captured +the sample. This happens in kernel context, at interrupt time, with no +userspace cooperation. The unwinder follows the ``%rbp`` chain, reading each +saved frame pointer from the target process's stack, until it reaches the +bottom of the stack or a configurable depth limit. The result is a compact +array of return addresses that ``perf`` resolves to symbols offline. This is +the lowest-overhead path: no data is copied to userspace beyond the address +array itself, and the kernel performs the walk in microseconds. + +When frame pointers are absent, ``perf_events`` **cannot unwind the stack +in-kernel at all**. The only alternative is ``--call-graph dwarf``, which does +not actually unwind in-kernel; instead, it copies up to 8 KB of raw stack +memory per sample into the ``perf.data`` ring buffer, and the unwinding is +performed offline in userspace by ``perf report``. This is not kernel-side +unwinding; it is a bulk memory copy followed by offline DWARF interpretation. + +eBPF is a Linux kernel technology that allows small programs to run safely +inside the kernel, enabling low-overhead system monitoring, profiling, and +tracing. Modern production profilers (Pyroscope, Parca, Datadog, Elastic) +increasingly use eBPF for continuous, always-on profiling. + +The kernel provides two BPF helper functions for capturing call stacks: + +* ``bpf_get_stackid(ctx, map, flags)`` walks the frame-pointer chain and + returns a hash key into a stack-trace map. It is the standard way to capture + call stacks in eBPF profilers, tracing tools, and bpftrace one-liners. It + walks frame pointers and **nothing else**: there is no DWARF fallback, no + SFrame fallback, no alternative unwinding path. + +* ``bpf_get_stack(ctx, buf, size, flags)`` writes the raw frame addresses into + a caller-provided buffer. Like ``bpf_get_stackid()``, it walks the + frame-pointer chain exclusively. + +Both helpers execute inside the kernel's BPF runtime, which enforces strict +safety constraints: bounded execution time, no unbounded loops, no arbitrary +memory access, and no calls to complex library code. These constraints make it +structurally impossible to implement a general-purpose DWARF unwinder as a BPF +helper. DWARF unwinding requires parsing variable-length instructions from +``.eh_frame`` sections, evaluating a stack machine (the DWARF Call Frame +Information state machine), and following arbitrarily deep chains of CIE/FDE +records, none of which can pass the BPF verifier. + +Without frame pointers, ``bpf_get_stackid()`` and ``bpf_get_stack()`` produce +truncated or empty results for Python processes. Every eBPF profiler in +production today (Pyroscope, Parca, Datadog's continuous profiler, Elastic +Universal Profiling, bpftrace, bcc's ``profile.py``) ultimately calls one of +these two helpers. When they fail, the profiler has no stack to report. + +Some vendors (Polar Signals, Elastic, OpenTelemetry's eBPF profiler, Yandex's +Perforator [#perforator]_) have implemented DWARF-in-eBPF as a workaround, but +this approach is substantially slower, more complex, and cannot use the +kernel's built-in stack-walking helpers. Instead of calling +``bpf_get_stackid()``, these implementations parse ``.eh_frame`` sections in +userspace, convert them to compact stack-delta lookup tables, load those tables +into BPF maps, and then evaluate the tables in a custom BPF program that +manually reads stack memory with ``bpf_probe_read_user()``. This requires 500+ +lines of BPF code (compared to fewer than 50 for the frame-pointer path), +demands per-process startup overhead to parse and load debug info, consumes +significant BPF map memory for the stack-delta tables, and is cutting-edge +vendor-specific infrastructure not available in standard tooling such as +bpftrace, bcc, or ``perf`` [#polarsignals]_. + +For the vast majority of eBPF use cases (bpftrace one-liners, bcc tools, custom +BPF programs for production monitoring), frame pointers are the only viable +unwinding mechanism because they are the only mechanism the kernel's built-in +helpers support. + +CPython's own documentation already states the recommended fix:: + + For best results, Python should be compiled with + CFLAGS='-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer' + as this allows profilers to unwind using only the frame pointer + and not on DWARF debug information. + + -- docs.python.org/3/howto/perf_profiling.html + +Production profiling tools echo this guidance. Grafana Pyroscope's +troubleshooting documentation states: "If your profiles show many shallow stack +traces, typically 1-2 frames deep, your binary might have been compiled without +frame pointers" [#pyroscope]_. + +If the recommended configuration is ``-fno-omit-frame-pointer``, it should be +the default. + +The Perf Trampoline Feature Requires Frame Pointers +--------------------------------------------------- + +Python 3.12 introduced ``-Xperf`` (``sys.activate_stack_trampoline``), which +generates small JIT stubs that make Python function names visible to ``perf``. +These stubs contain no DWARF information; the only way a profiler can walk +through them is via the frame-pointer chain. The ``-Xperf`` feature as shipped +in 3.12 therefore produces broken stacks on any installation that was not +explicitly rebuilt with ``-fno-omit-frame-pointer``. + +Python 3.13 added ``-Xperf_jit``, a DWARF-based alternative, but it requires +``perf`` >= 6.8, produces substantially larger data files than the +frame-pointer path, and is not suitable for continuous production profiling due +to its per-sample overhead. + +Distributions Are Waiting for Upstream +-------------------------------------- + +Fedora 38 [#fedora38]_, Ubuntu 24.04 LTS [#ubuntu2404]_, and Arch Linux have +all rebuilt their entire package trees with ``-fno-omit-frame-pointer +-mno-omit-leaf-frame-pointer``. However, Ubuntu 24.04 LTS explicitly exempted +CPython:: + + In cases where the impact is high (such as the Python + interpreter), we'll continue to omit frame pointers until + this is addressed. + + -- ubuntu.com/blog/ubuntu-performance-engineering-with- + frame-pointers-by-default + +The result is a circular dependency: the runtime most in need of frame pointers +for profiling is the one that major distributions leave without them, pending +an upstream fix. Red Hat Enterprise Linux and CentOS Stream also disable frame +pointers by default, investing instead in alternative approaches +(``eu-stacktrace``, SFrame) that are not yet production-ready (see +`Alternatives to Frame-Pointer Unwinding`_). Users who install Python from +python.org, build from source, use pyenv, or work on Debian, RHEL, openSUSE, or +any other distribution that has not adopted frame pointers system-wide get no +frame pointers regardless of what their local distribution does. An upstream +default resolves this permanently. + +Mixed Python/C Profiling Requires a Continuous Chain +---------------------------------------------------- + +Real Python applications spend substantial time in C extension modules: NumPy, +cryptographic libraries, compression, database drivers, and so on. For a +``perf`` flame graph to show the full path from Python code through a C +extension and into a system library, the frame-pointer chain must be continuous +through the interpreter **and** through every extension in the call stack. A +gap at any point, whether in ``_PyEval_EvalFrameDefault`` or in a C extension, +breaks the chain for the entire process. + +The need for a continuous chain is precisely why the flags must propagate to +extension builds. If only the interpreter has frame pointers but extensions do +not, the chain is still broken at every C extension boundary. By adding the +flags to ``CFLAGS`` as reported by ``sysconfig``, extension builds that consume +CPython's compiler flags (for example via ``pip install``, ``setuptools``, or +``python setup.py build``) will inherit frame pointers by default. Extensions +and libraries with independent build systems still need to enable the same +flags themselves for the frame-pointer chain to remain continuous. + +The JIT Compiler Needs Frame Pointers to Be Debuggable +------------------------------------------------------ + +CPython's copy-and-patch JIT (:pep:`744`) generates native machine code at +runtime. Without frame pointers in that generated code, stack unwinding +through JIT frames is broken for virtually every tool in the ecosystem: GDB, +LLDB, libunwind, libdw (elfutils), py-spy, Austin, pystack, memray, ``perf``, +and all eBPF-based profilers. + +The investigation in issue `#126910`_ found that compiling the JIT stencils +with ``-fno-omit-frame-pointer`` and ``-mno-omit-leaf-frame-pointer`` is a +two-line change that would make most existing debuggers and profilers work with +JIT-compiled code immediately. The measured overhead is approximately 2% on +x86-64 and even lower on AArch64 (which has a dedicated link register). This +is a remarkably good outcome: other JIT compilers (V8, LuaJIT, .NET CoreCLR, +Julia, LLVM's ORC JIT) typically require hundreds to thousands of lines of code +to implement custom DWARF ``.eh_frame`` generation, GDB JIT interface support +(``__jit_debug_register_code``), and per-unwinder registration APIs +(``_U_dyn_register``, ``__register_frame``). CPython's JIT may get most of the +benefit from frame pointers alone if that follow-up change is adopted. + +Critically, for JIT frame pointers to produce useful results, the interpreter +itself must also have frame pointers. A JIT-compiled function calls back into +the interpreter for many operations; if the interpreter frames lack frame +pointers, the unwinder hits a gap and the stack trace is truncated. This PEP +addresses that interpreter-side gap. JIT stencil flags (issue `#126910`_) are +a complementary follow-up needed for complete stack unwinding in the presence +of the JIT. + +The Ecosystem Has Already Adopted Frame Pointers +------------------------------------------------ + +The shift toward frame pointers has already happened independently of CPython +upstream, and at massive scale. + +``python-build-standalone``, the hermetic Python distribution used by ``uv``, +``mise``, ``rye``, and many CI systems, enabled ``-fno-omit-frame-pointer`` on +all x86-64 and AArch64 Linux builds in early 2026 and shipped in ``uv`` 0.11.0 +[#pbs992]_. Gregory Szorc, the project's creator, stated: "Frame pointers +should be enabled on 100% of x86-64 / aarch64 binaries in 2026. Full stop." He +further argued: "We shouldn't stop at enabling frame pointers in PBS: we should +advocate CPython enable them by default not only in the core interpreter but +also for compiled C extensions." [#pbs992]_ + +This means that a large and growing fraction of Python users (everyone using +``uv python install``, Astral's GitHub Actions, or any tool that fetches +``python-build-standalone`` binaries) is already running Python with frame +pointers. The interpreter they use daily already has frame pointers enabled; +this PEP makes the upstream default match that reality. + +The ``python-build-standalone`` benchmarks measured 1-3% overhead across Python +3.11 through 3.15, with 1.1% on a non-tail-call build and up to 3.3% on the +tail-call interpreter [#pbs992]_. These numbers are consistent with this PEP's +first-party measurements and with Fedora/Ubuntu data. + +Major Linux distributions (Fedora 38 [#fedora38]_, Ubuntu 24.04 [#ubuntu2404]_, +Arch Linux) have rebuilt their entire package trees with frame pointers. +PyTorch, Node.js, Redis, Go, and .NET have all adopted frame pointers in their +default builds (see `Industry Consensus Has Shifted Decisively`_ in the +Rationale for the full list). + +An upstream default aligns CPython with the reality that the ecosystem has +already adopted. + + +Specification +============= + +Build System Changes +-------------------- + +The following changes are made to ``configure.ac``:: + + AX_CHECK_COMPILE_FLAG([-fno-omit-frame-pointer], + [CFLAGS="$CFLAGS -fno-omit-frame-pointer"]) + AX_CHECK_COMPILE_FLAG([-mno-omit-leaf-frame-pointer], + [CFLAGS="$CFLAGS -mno-omit-leaf-frame-pointer"]) + +Using ``CFLAGS`` ensures: + +1. The flags apply to all ``*.c`` files compiled as part of the interpreter: + the ``python`` binary, ``libpython``, and built-in extension modules under + ``Modules/``. +2. The flags **are** written into the ``sysconfig`` data, so that third-party C + extensions built against this Python (via ``pip``, ``setuptools``, or direct + ``sysconfig`` queries) inherit frame pointers by default. + +This is an intentional design choice. For profiling data to be useful, the +frame-pointer chain must be continuous through the entire call stack. A gap at +any C extension boundary is as harmful as a gap in the interpreter itself. By +propagating the flags, CPython establishes frame pointers as the ecosystem-wide +default for the Python stack. + +``-mno-omit-leaf-frame-pointer`` preserves the frame pointer even in leaf +functions. Without it, the compiler may drop the frame pointer in any function +that makes no further calls, even when ``-fno-omit-frame-pointer`` is set. +Fedora, Ubuntu, and Arch Linux all include this flag; it ensures a profiler +sampling inside a leaf function still recovers a complete call chain. + +Opt-Out Configure Flag +---------------------- + +A new ``configure`` option is added:: + + --without-frame-pointers + +When specified, neither flag is added to ``CFLAGS``. This is appropriate for +deployments that have measured an unacceptable regression on their specific +workload, or for distributions that inject frame-pointer flags at a higher +level and wish to avoid double-specification, analogous to Fedora's per-package +``%undefine _include_frame_pointers`` macro. + +Extension authors who wish to override the default for a specific module can +pass ``-fomit-frame-pointer`` in their ``extra_compile_args`` or via +environment variables; the last flag on the command line wins under GCC and +Clang. + +Ecosystem Impact +---------------- + +Because the flags are in ``CFLAGS``, they propagate automatically to consumers +that build against CPython's reported compiler flags, such as C extensions +built via ``pip``, ``setuptools``, or direct ``sysconfig`` queries. Those +consumers need take no additional action to benefit from this change. + +Not all compiled code in the Python ecosystem inherits CPython's ``CFLAGS``. +Rust extensions built with ``pyo3`` or ``maturin``, C++ libraries with their +own build systems, and embedding applications that compile CPython from source +each manage their own compiler flags. This PEP recommends that all such +projects also enable ``-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer`` +in their builds. A frame-pointer chain is only as complete as its weakest +link: a single library in the call stack without frame pointers breaks the +chain for the entire process, regardless of whether CPython and every other +library has them. The goal is that every native component in a Python process +participates in the frame-pointer chain, so that ``perf record`` and eBPF +profilers produce complete, useful flame graphs out of the box. + +Extension authors who observe an unacceptable regression in a specific module +can opt out per-extension via ``extra_compile_args`` (see `Extension Build +Impact`_). Distributions that already enable frame pointers system-wide +(Fedora, Ubuntu, Arch Linux) need take no action. + +Documentation Updates +--------------------- + +``Doc/howto/perf_profiling.rst`` is updated to note that frame pointers are +enabled by default from Python 3.15, and to retain the ``CFLAGS`` +recommendation for earlier versions. + +``Doc/using/configure.rst`` is updated to document ``--without-frame-pointers``. + +Platform Scope +-------------- + +Both flags are accepted by GCC and Clang on all supported Linux architectures +(x86-64, AArch64, s390x, RISC-V, ARM). On macOS with Apple Silicon, the ARM64 +ABI mandates frame pointers; the flags are redundant but harmless. + +On Windows x64, MSVC does not use frame pointers for stack unwinding. Instead, +the Windows x64 ABI mandates ``.pdata`` / ``.xdata`` unwind metadata for every +non-leaf function [#msvc_x64_eh]_: the compiler emits ``RUNTIME_FUNCTION`` and +``UNWIND_INFO`` structures that describe how each function's prologue modifies +the stack, allowing the OS unwinder to walk the stack using RSP and +statically-known frame sizes without a frame-pointer chain. This metadata is +always present and always correct, so profilers, debuggers, and ETW-based +tracing on Windows x64 already produce reliable call stacks without frame +pointers. The ``/Oy`` (frame-pointer omission) flag is only available for +32-bit x86 MSVC targets; it does not exist for x64 [#msvc_oy]_. The GCC/Clang +flags proposed by this PEP have no effect on MSVC builds. + +On Windows ARM64, the ABI requires frame pointers (``x29``) for compatibility +with ETW-based fast stack walking [#msvc_arm64_abi]_. Frame pointers are +enabled by default and no action is needed. + +The ``AX_CHECK_COMPILE_FLAG`` guards silently skip any flag the compiler does +not accept, making the change safe across all platforms and toolchains. + + +Rationale +========= + +Frame Pointers Are a Low-Cost, High-Value Default +------------------------------------------------- + +The rationale for omitting frame pointers (freeing one general-purpose +register, or GPR) was meaningful on 32-bit x86, where ``%ebp`` represented a +~20% increase in usable registers (5 to 6). On x86-64 the gain is under 7% (15 +to 16 registers); on AArch64 with its 31 GPRs it is negligible. + +Empirical measurements from production deployments are consistent: + +* Brendan Gregg (OpenAI, formerly Netflix): "I've enabled frame pointers at + huge scale for Java and glibc... typically less than 1% and usually so close + to zero that it is hard to measure." [#gregg2024]_ +* Meta: Internal benchmarks on their two most performance-sensitive + applications "did not show significant impact on performance," as reported in + the Fedora 38 Change proposal authored by Daan De Meyer, Davide Cavalca, and + Andrii Nakryiko (all Meta/Facebook) [#fedora38]_. Google similarly compiles + all internal critical software with frame pointers [#fedora38]_. +* Ubuntu 24.04 analysis: "The penalty on 64-bit architectures is between 1-2% + in most cases." [#ubuntu2404]_ +* Fedora 38 test suite: individual benchmark regressions of approximately 2% + (kernel compilation 2.4%, Blender rendering 2%) [#fedora38]_. + +The pyperformance ``scimark_sparse_mat_mult`` benchmark regressed 9.5% in +Fedora's testing, the worst case in that run (see `Detailed Performance +Analysis of CPython with Frame Pointers`_ below); first-party measurements on +CPython 3.15-dev show larger individual regressions on ``xml_etree_*`` +benchmarks (up to 1.31x), though the geometric mean remains around 1%. These +worst-case benchmarks exercise C helper function calls almost exclusively; real +applications distribute CPU time across the interpreter, C extensions, I/O, and +system calls. + +A common misconception in the community is that frame pointers carry large +overhead "because there was a single Python case that had a +10% slowdown." +[#hn-fp]_ That single case is the eval loop benchmark; the geometric mean +across real workloads is 1-2%. + +Detailed Performance Analysis of CPython with Frame Pointers +------------------------------------------------------------ + +**In short:** the overhead comes not from the eval loop (which already uses +frame pointers in both builds) but from ~6,000 smaller C helper functions +gaining 4-byte prologues and losing one GPR. The measured cost is +5.5% more +instructions and +3.3% wall time on C-call-heavy workloads, with no cache or +branch-prediction pathologies. + +To understand the overhead precisely, a controlled binary-level and +microarchitectural analysis was performed on CPython 3.15-dev. Both builds +used the same commit, the same compiler (GCC), the same flags (``-O3 -DNDEBUG +-g``), and ran on the same machine (x86-64, Intel, pinned to a single P-core to +eliminate scheduling noise). The only difference was the presence or absence +of ``-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer``. + +A common misconception is that the frame-pointer overhead comes primarily from +``_PyEval_EvalFrameDefault``, the bytecode dispatch function. Andrii Nakryiko +(Meta, BPF kernel maintainer) analysed the regression on Python 3.11 and found +that function grew significantly with frame pointers [#discuss22507]_. On the +current codebase (3.15-dev with the DSL-generated eval loop), however, this is +no longer the case. GCC already generates a frame-pointer prologue for +``_PyEval_EvalFrameDefault`` in *both* builds, because the function is ~60 KB +with deep nesting and the compiler keeps ``%rbp`` as a frame pointer regardless +of the flag. The function is 59,549 bytes with the flag and 59,602 bytes +without (0.1% difference). The hot bytecode dispatch handlers (``STORE_FAST``, +``LOAD_FAST``, etc.) are instruction-for-instruction identical in both builds. +Eval-loop-dominated workloads are actually 1-2% *faster* with frame pointers, +because the different register allocation produces a code layout that reduces +instruction-fetch stalls (frontend-bound fraction drops from 24.1% to 19.4%, +IPC improves from 4.83 to 5.06). + +The overhead instead comes from the approximately 6,000 smaller C helper +functions that gain frame-pointer prologues (``push %rbp; mov %rsp,%rbp`` at +entry, ``pop %rbp`` at exit). In the baseline build, only 84 out of 7,471 text +symbols have frame-pointer prologues (1.1%); with ``-fno-omit-frame-pointer``, +6,009 do (80.4%). Each function also loses ``%rbp`` as a general-purpose +register, forcing the compiler to shift values to other registers or spill them +to the stack. For example, ``insertdict`` (one of the hottest C functions in +CPython, ~20% of cycles in dict-heavy workloads) has the same code size (1,055 +bytes) in both builds, but in the baseline build ``%rbp`` holds a function +argument directly (zero cost), while the frame-pointer build must shift that +argument to ``%r12``, the key argument to ``%r13``, and the stack frame grows +from 40 to 56 bytes to accommodate the displaced values. + +Across a tight loop that calls ~10 C helper functions per iteration +(``insertdict``, ``_Py_dict_lookup``, ``unicodekeys_lookup_unicode``, +``PyDict_SetItem``, etc.), the prologue/epilogue instructions and register +spills add up to +5.5% more dynamic instructions (167.5 billion vs 158.8 +billion over 100M iterations). That instruction-count increase directly +explains the measured +3.3% wall-time overhead on C-function-call-heavy +workloads. + +Intel Top-Down Method analysis of the slower (C-call-heavy) workload confirms +the overhead is entirely additional work, not work that executes badly: + +========================= ============ ============= ============ +Metric FP Build Baseline Delta +========================= ============ ============= ============ +Wall time 10.27 s 9.94 s +3.3% +Instructions 167.5 B 158.8 B +5.5% +IPC 5.11 5.00 +2.1% +Retiring (useful work) 78.1% 75.5% +2.6 pp +Frontend bound 20.4% 23.1% -2.7 pp +Backend bound 1.1% 0.9% +0.2 pp +L1 dcache load misses 2.02 M 2.08 M -3.1% +L1 icache load misses 4.87 M 4.91 M -0.9% +Branch misses 473 K 471 K +0.4% +========================= ============ ============= ============ + +The retiring rate is *higher* with frame pointers (the CPU spends more of its +time doing useful work), the frontend-bound fraction is *lower*, and cache miss +rates are comparable or marginally improved. The extra stack spill/reload +traffic adds ~3% more total L1 data-cache load operations (not shown in the +table above, which reports only L1 load *misses*), and those additional loads +all hit L1. There are no cache blowouts, no TLB pressure increases, no +branch-prediction pathologies. The overhead is predictable, bounded, and +carries no risk of surprising regressions on different hardware or workloads. + +The ``.text`` section is 0.5% *smaller* in the frame-pointer build (5,658,071 +vs 5,686,703 bytes), because ``%rbp``-relative addressing often produces more +compact encodings than ``%rsp`` + SIB addressing, and simpler epilogues (a +``pop`` chain vs ``add $N,%rsp``) also save bytes. Binary size is not a +concern. + +Finally, the structural trend in CPython favours frame pointers. CPython 3.11's +specialising adaptive interpreter, 3.12's DSL-generated eval loop, and the +experimental copy-and-patch JIT (:pep:`744`, introduced in 3.13) progressively +shift hot execution away from the generic C helper path. As more bytecodes are +handled by specialised or JIT-compiled code, the proportion of time spent in +these helper functions decreases, and the frame-pointer overhead decreases with +it. + +Industry Consensus Has Shifted Decisively +----------------------------------------- + +The decision to omit frame pointers by default dates from the early 2000s, +formalised by GCC 4.6 in 2011. The industry has since broadly reversed course: + +* Go 1.7 (2016): Frame pointers enabled by default on x86-64 [#go17]_. Russ + Cox: "Having frame pointers on by default means that Linux perf, Intel VTune, + and other profilers can grab Go stack traces much more efficiently" + [#go_fp_issue]_. The Go team explicitly traded the ~2% overhead for + observability. +* Rust standard library (2024): PR #122646 enabled frame pointers in the + precompiled standard library shipped with official Rust toolchains, with a + measured 0.3% instruction-count regression and no cycles regressions + [#rust_fp]_. +* Chromium: The GN build system defaults ``enable_frame_pointers`` to ``true`` + on all desktop Linux and macOS builds, one of the largest C++ projects in the + world [#chromium_fp]_. +* .NET CoreCLR: Frame pointers enabled by default on Linux and macOS x64 since + inception, to aid native OS tooling for stack unwinding [#dotnet_fp]_. +* Node.js: Has compiled its C++ runtime with ``-fno-omit-frame-pointer`` since + 2013; an attempt to remove the flag in September 2022 was reverted because + ``perf`` profiling broke at C++/JS transitions [#nodejspr]_. +* PyTorch: Enables ``-fno-omit-frame-pointer`` on AArch64 builds + unconditionally, noting that "aarch64 C++ stack unwinding uses frame-pointer + chain walking, so frame pointers must be present in all build types" + [#pytorch]_. +* Redis: Adopted ``-fno-omit-frame-pointer`` following Fedora 38, noting "Redis + benchmarks do not seem to be significantly impacted when built with frame + pointers." [#redis]_ +* Fedora 38 [#fedora38]_, Ubuntu 24.04 [#ubuntu2404]_, Arch Linux, AlmaLinux + Kitten 10 [#almalinux_fp]_: All system packages (except CPython on Ubuntu) + rebuilt with frame pointers. AlmaLinux explicitly diverged from RHEL/CentOS + Stream, which disable frame pointers. +* python-build-standalone: All x86-64 and AArch64 Linux builds ship with frame + pointers since early 2026 [#pbs992]_. + +CPython has not yet adopted this change. + +Why Not Use ``CFLAGS_NODIST`` Instead of ``CFLAGS`` +--------------------------------------------------- + +CPython's build system provides ``CFLAGS_NODIST`` specifically for flags that +should apply to the interpreter but not propagate to extension module builds +via ``sysconfig``. Using ``CFLAGS_NODIST`` would confine the overhead to the +interpreter itself. + +This PEP deliberately chooses ``CFLAGS`` over ``CFLAGS_NODIST`` because frame +pointers are only useful when the chain is continuous. Unlike debugging aids +such as sanitizers or assertions, which are useful even when applied to a +single component, a frame-pointer chain with a gap at a C extension boundary +produces the same broken stack trace as no frame pointers at all. The +profiler, debugger, or eBPF tool cannot skip the gap and resume unwinding. + +This distinguishes frame pointers from other flags placed in ``CFLAGS_NODIST``: +those flags (such as ``-Werror`` or internal warning suppressions) are +correctness or policy controls that are meaningful per-compilation-unit. Frame +pointers are an ecosystem-wide property that is only effective when all +participants cooperate. The 1-2% overhead measured on CPython is driven by its +high density of small C helper function calls; typical C extension code does +not exhibit the same call density and sees negligible overhead. + +As Gregory Szorc (``python-build-standalone`` creator) noted: "Turning the +corner on the long tail of compiled extensions having frame pointers will take +years. So the sooner we start..." [#pbs992]_ Propagating the flags via +``CFLAGS`` is how CPython starts that process. + +Alternatives to Frame-Pointer Unwinding +--------------------------------------- + +Several alternatives to frame-pointer-based unwinding exist; none is an +adequate substitute today. + +DWARF CFI (``perf --call-graph dwarf``) is discussed in `Profilers Are Slower +and Less Accurate Without Frame Pointers`_: it copies 8 KB of stack per sample, +produces much larger data files, and cannot be used in BPF context [#redhat]_. + +Intel LBR (Last Branch Record) is limited to 16-32 frames, requires Intel +hardware, and is unavailable in virtual machines and cloud environments +[#intel_lbr]_. + +DWARF-in-eBPF (Polar Signals, Elastic Universal Profiling, OpenTelemetry's eBPF +profiler, Yandex Perforator [#perforator]_) bypasses the kernel's built-in +``bpf_get_stackid()`` / ``bpf_get_stack()`` helpers entirely and reimplements +stack walking from scratch inside BPF. This is slower (each sample requires +multiple ``bpf_probe_read_user()`` calls and BPF map lookups instead of a +single helper call), more complex (500+ lines of BPF code vs. fewer than 50 for +the frame-pointer path), and requires per-process startup overhead to parse +``.eh_frame`` and load stack-delta tables into BPF maps. It is vendor-specific +infrastructure unavailable in bpftrace, bcc, ``perf``, or any standard tooling +[#polarsignals]_. + +SFrame (Simple Frame format) is a lightweight stack unwinding format merged +into the Linux kernel in version 6.3 (April 2023) and supported by GNU binutils +for generating ``.sframe`` sections. It is designed to be simple enough for +BPF-based unwinding without frame pointers. However, as of early 2026: +``bpf_get_stackid()`` does not support SFrame; no production-ready profiling +toolchain uses it; ``perf`` has no SFrame-based call-graph mode; and SFrame +support in userspace tools (GDB, libunwind, libdw) is absent or experimental. +Brendan Gregg has estimated SFrame ecosystem maturity around 2029 +[#gregg2024]_. The intervening years of Python deployments should not be left +without usable system-level profiling. This decision can be revisited if +SFrame achieves ecosystem parity. + +Frame-pointer unwinding remains the only method that is simultaneously: +kernel-side, async-signal-safe, BPF-compatible, depth-unlimited, and produces +compact profiling data. It is the method that works everywhere with no +additional configuration. + + +Backwards Compatibility +======================= + +Binary Compatibility +-------------------- + +Enabling frame pointers does not change the Python ABI. The stable ABI +(:pep:`384`), the limited C API, and the ``PyObject`` memory layout are all +unaffected. No compiled extension module will fail to load or behave +incorrectly. + +Performance +----------- + +.. TODO: Insert full pyperformance results here once data collection + is complete. + +This overhead applies to both the interpreter and to C extensions that inherit +the flags via ``sysconfig``. Detailed microarchitectural analysis shows the +overhead is purely from additional instructions (frame-pointer prologues in +~6,000 helper functions), with no pathological cache, TLB, or branch-prediction +effects (see `Detailed Performance Analysis of CPython with Frame Pointers`_). +Typical C extension code does not exhibit the same density of small function +calls as the CPython runtime. Numerically intensive extensions (NumPy, SciPy) +typically spend their hot loops in BLAS/LAPACK or vectorised intrinsics that +are compiled separately and unaffected by Python's ``CFLAGS``. Extensions with +hot scalar C loops (e.g., Cython-generated code) may see measurable but modest +overhead. + +For context, 1-2% geometric mean is comparable to overhead routinely accepted +for build-time defaults such as ``-fstack-protector-strong`` (security) and the +ASLR-compatible ``-fPIC`` flag for shared libraries. In return, the entire +Python ecosystem gains the ability to produce complete flame graphs, accurate +profiler output, and reliable debugger backtraces, capabilities that are +currently broken or unavailable for the majority of Python installations. This +is a substantial return on a modest cost. Deployments where even this cost is +unacceptable may use ``--without-frame-pointers``. + +Extension Build Impact +---------------------- + +C extensions built against Python 3.15+ will inherit +``-fno-omit-frame-pointer`` and ``-mno-omit-leaf-frame-pointer`` in their +default ``CFLAGS`` from ``sysconfig``. This is the same mechanism by which +extensions already inherit ``-O2``, warning flags, and other compilation +defaults. + +Extensions that set their own ``CFLAGS`` or use ``extra_compile_args`` in +``setup.py`` / ``pyproject.toml`` can override this default. The last flag on +the command line wins, so appending ``-fomit-frame-pointer`` is sufficient to +opt out on a per-extension basis. + +Build Reproducibility +--------------------- + +Deterministic flags are added to a deterministic build stage; builds that were +previously reproducible remain so. + + +Security Implications +===================== + +This change has no security impact. Frame pointers are a compiler convention +for laying out stack frames; they do not introduce new attack surface or expose +information not already available through CPython's existing interfaces. + + +How to Teach This +================= + +No teaching is required. This change is invisible to Python users: no APIs +change, no behaviour changes, and no user action is needed. The only observable +effect is that profilers, debuggers, and system-level tracing tools produce +more complete and more reliable results out of the box. + + +Reference Implementation +======================== + +`github.com/pablogsal/cpython, branch frame-pointers +`_ + + +Footnotes +========= + +.. [#gregg2024] Brendan Gregg, "The Return of the Frame Pointers", + March 2024. + https://www.brendangregg.com/blog/2024-03-17/the-return-of-the-frame-pointers.html + +.. [#fedora38] Fedora Change Proposal: fno-omit-frame-pointer. + Authors: Daan De Meyer, Davide Cavalca, Andrii Nakryiko (Meta). + https://fedoraproject.org/wiki/Changes/fno-omit-frame-pointer + +.. [#ubuntu2404] Canonical, "Performance engineering on Ubuntu leaps + forward with frame pointers by default in Ubuntu 24.04 LTS", 2024. + https://ubuntu.com/blog/ubuntu-performance-engineering-with-frame-pointers-by-default + +.. [#discuss22507] Daan De Meyer, Andrii Nakryiko et al., "Python 3.11 + performance with frame pointers", discuss.python.org, January 2023. + https://discuss.python.org/t/python-3-11-performance-with-frame-pointers/22507 + +.. [#hn-fp] Hacker News, "The return of the frame pointers", March 2024. + https://news.ycombinator.com/item?id=39731824 + +.. [#go17] Go 1.7 Release Notes. + https://tip.golang.org/doc/go1.7 + +.. [#go_fp_issue] Go issue #15840, "cmd/compile: enable frame pointer + by default", opened by Russ Cox, May 2016. + https://github.com/golang/go/issues/15840 + +.. [#nodejspr] Node.js PR #44452, "build: go faster, drop + -fno-omit-frame-pointer", September 2022 (reverted). + https://github.com/nodejs/node/pull/44452 + +.. [#pytorch] PyTorch, ``-fno-omit-frame-pointer`` for AArch64 in + ``CMakeLists.txt``. + https://github.com/pytorch/pytorch/blob/main/CMakeLists.txt + +.. [#redis] Redis issue #12861, "Add -fno-omit-frame-pointer to + default compilation flags", December 2023. + https://github.com/redis/redis/issues/12861 + +.. [#redhat] Red Hat Developer, "Frame pointers: Untangling the + unwinding", July 2023. + https://developers.redhat.com/articles/2023/07/31/frame-pointers-untangling-unwinding + +.. [#polarsignals] Polar Signals, "DWARF-based Stack Walking Using + eBPF", November 2022. + https://www.polarsignals.com/blog/posts/2022/11/29/dwarf-based-stack-walking-using-ebpf + +.. [#pbs992] python-build-standalone issue #992, "Enable frame + pointers for Linux perf profiling", resolved 2026. + https://github.com/astral-sh/python-build-standalone/issues/992 + +.. [#gcc_fomit] GCC Manual, "-fomit-frame-pointer", Code Generation + Options. + https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fomit-frame-pointer + +.. [#torvalds_fp] LWN.net, "Unwinding the stack: the ORC unwinder", + September 2017. Torvalds: "I do not ever again want to see fancy + unwinders with complex state machine handling." + https://lwn.net/Articles/728339/ + +.. [#dotnet_fp] .NET Runtime, ``add_compile_options(-fno-omit-frame-pointer)`` + in ``eng/native/configurecompiler.cmake``, GitHub. + https://github.com/dotnet/runtime/blob/main/eng/native/configurecompiler.cmake + +.. [#intel_lbr] Intel, "Last Branch Records", Intel 64 and IA-32 + Architectures Software Developer's Manual, Volume 3, Chapter 18. + +.. [#msvc_x64_eh] Microsoft, "x64 exception handling", MSVC + documentation. + https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64 + +.. [#msvc_oy] Microsoft, "/Oy (Frame-Pointer Omission)", MSVC + documentation. + https://learn.microsoft.com/en-us/cpp/build/reference/oy-frame-pointer-omission + +.. [#msvc_arm64_abi] Microsoft, "Overview of ARM64 ABI conventions", + MSVC documentation. + https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions + +.. [#rust_fp] Rust PR #122646, "Enable frame pointers for the standard + library", merged March 2024. + https://github.com/rust-lang/rust/pull/122646 + +.. [#chromium_fp] Chromium, ``enable_frame_pointers`` in + ``build/config/compiler/compiler.gni``. + https://chromium.googlesource.com/chromium/src/build/+/refs/heads/main/config/compiler/compiler.gni + +.. [#almalinux_fp] AlmaLinux, "Introducing AlmaLinux OS Kitten 10", + October 2024. "We are re-enabling [frame pointers]." + https://almalinux.org/blog/2024-10-22-introducing-almalinux-os-kitten/ + +.. [#perforator] Yandex, "Perforator: cluster-wide continuous + profiling tool", open-sourced January 2025. + https://github.com/yandex/perforator + +.. [#pyroscope] Grafana Pyroscope, "eBPF profiling troubleshooting", + Grafana documentation. + https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/ebpf/troubleshooting/ + +.. [#libunwind] libunwind, "A portable and efficient C programming + interface to determine the call-chain of a program". + https://www.nongnu.org/libunwind/ + +.. [#framehop] framehop, "Stack frame unwinding for profilers", + by Markus Stange. + https://github.com/mstange/framehop + +.. [#samply] samply, "A command-line sampling profiler for macOS + and Linux", by Markus Stange. + https://github.com/mstange/samply + +.. _#96174: https://github.com/python/cpython/issues/96174 +.. _python/cpython issue #96174: https://github.com/python/cpython/issues/96174 +.. _#126910: https://github.com/python/cpython/issues/126910 + + +Copyright +========= + +This document is placed in the public domain or under the CC0-1.0-Universal +license, whichever is more permissive. From 984672f2efe87ac80ccc1187ba341d1ccd1ca1fd Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 10:38:56 -0700 Subject: [PATCH 02/21] First pass at edits --- peps/pep-0830.rst | 84 +++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 4d7f2b051ca..c50cb96d6ee 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -2,7 +2,7 @@ PEP: 830 Title: Frame Pointers Everywhere: Enabling System-Level Observability for Python Author: Pablo Galindo Salgado , Ken Jin , - Savannah Ostrowski , + Savannah Ostrowski , Diego Russo Discussions-To: Status: Draft @@ -15,7 +15,7 @@ Post-History: Abstract ======== -This PEP does two things: +This PEP proposes two things: 1. **Build CPython with frame pointers by default on platforms that support them.** The default build configuration is changed to compile the @@ -51,9 +51,9 @@ Motivation Python's observability story (profiling, debugging, and system-level tracing) is fundamentally limited by the absence of frame pointers. The core motivation -of this PEP is to make Python observable by default: profilers faster and more -accurate, debuggers more reliable, and eBPF-based tools functional without -workarounds. +of this PEP is to make Python observable by default, so that profilers are faster +and more accurate, debuggers are more reliable, and eBPF-based tools are functional +without workarounds. Today, users who want to profile CPython with system tools must rebuild the interpreter with special compiler flags, a step that most users cannot or will @@ -201,10 +201,10 @@ processes. The Linux kernel has no DWARF unwinder and, per Linus Torvalds, will not gain one [#torvalds_fp]_; the kernel developed its own ORC format for internal use instead. -The impact extends beyond CPU profiling. Off-CPU flame graphs (used to +The impact extends beyond CPU profiling. Off-CPU flamegraphs (used to diagnose latency caused by I/O waits, lock contention, and scheduling delays) rely on the same ``bpf_get_stackid()`` helper to capture the stack at the point -where a thread blocks. As Brendan Gregg notes, off-CPU flame graphs "can be +where a thread blocks. As Brendan Gregg notes, off-CPU flamegraphs "can be dominated by libc read/write and mutex functions, so without frame pointers end up mostly broken" [#gregg2024]_. For Python services where latency matters more than raw CPU throughput, off-CPU profiling is often the most valuable @@ -405,30 +405,24 @@ The JIT Compiler Needs Frame Pointers to Be Debuggable ------------------------------------------------------ CPython's copy-and-patch JIT (:pep:`744`) generates native machine code at -runtime. Without frame pointers in that generated code, stack unwinding -through JIT frames is broken for virtually every tool in the ecosystem: GDB, -LLDB, libunwind, libdw (elfutils), py-spy, Austin, pystack, memray, ``perf``, -and all eBPF-based profilers. - -The investigation in issue `#126910`_ found that compiling the JIT stencils -with ``-fno-omit-frame-pointer`` and ``-mno-omit-leaf-frame-pointer`` is a -two-line change that would make most existing debuggers and profilers work with -JIT-compiled code immediately. The measured overhead is approximately 2% on -x86-64 and even lower on AArch64 (which has a dedicated link register). This -is a remarkably good outcome: other JIT compilers (V8, LuaJIT, .NET CoreCLR, -Julia, LLVM's ORC JIT) typically require hundreds to thousands of lines of code -to implement custom DWARF ``.eh_frame`` generation, GDB JIT interface support +runtime. Without frame pointers in the interpreter, stack unwinding through +JIT frames is broken for virtually every tool in the ecosystem: GDB, LLDB, +libunwind, libdw (elfutils), py-spy, Austin, pystack, memray, ``perf``, and +all eBPF-based profilers. Ensuring full-stack observability for JIT-compiled +code is a prerequisite for the JIT to be considered production-ready. + +Individual JIT stencils do not need frame-pointer prologues; the entire JIT +region can be treated as a single frameless region for unwinding purposes. +What matters is that the interpreter itself is built with frame pointers, so +that the frame-pointer register (``%rbp`` on x86-64, ``x29`` on AArch64) is +reserved and not clobbered by stencil code. With frame pointers in the +interpreter, unwinders can walk through JIT regions without needing to inspect +individual stencils. This is a remarkably good outcome compared to other +JIT compilers (V8, LuaJIT, .NET CoreCLR, Julia, LLVM's ORC JIT), which +typically require hundreds to thousands of lines of code to implement custom +DWARF ``.eh_frame`` generation, GDB JIT interface support (``__jit_debug_register_code``), and per-unwinder registration APIs -(``_U_dyn_register``, ``__register_frame``). CPython's JIT may get most of the -benefit from frame pointers alone if that follow-up change is adopted. - -Critically, for JIT frame pointers to produce useful results, the interpreter -itself must also have frame pointers. A JIT-compiled function calls back into -the interpreter for many operations; if the interpreter frames lack frame -pointers, the unwinder hits a gap and the stack trace is truncated. This PEP -addresses that interpreter-side gap. JIT stencil flags (issue `#126910`_) are -a complementary follow-up needed for complete stack unwinding in the presence -of the JIT. +(``_U_dyn_register``, ``__register_frame``). The Ecosystem Has Already Adopted Frame Pointers ------------------------------------------------ @@ -836,8 +830,21 @@ incorrectly. Performance ----------- -.. TODO: Insert full pyperformance results here once data collection - is complete. +Full pyperformance results comparing the frame-pointer build against an +identical build without frame pointers (geometric mean and per-benchmark +range, 108 benchmarks): + +===================================== ======================= +Machine Geometric mean overhead +===================================== ======================= +Apple M2 Mac Mini (arm64, macOS) 1.01x slower +Intel Xeon Platinum 8480 (x86-64) 1.01x slower +AMD EPYC 9654 (x86-64) 1.01x slower +AWS Graviton c7g.16xlarge (aarch64) 1.02x slower +Ampere Altra Max (aarch64) 1.01x slower +Raspberry Pi (aarch64) +X.X% +macOS M3 (arm64) +X.X% +===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit the flags via ``sysconfig``. Detailed microarchitectural analysis shows the @@ -892,10 +899,15 @@ information not already available through CPython's existing interfaces. How to Teach This ================= -No teaching is required. This change is invisible to Python users: no APIs -change, no behaviour changes, and no user action is needed. The only observable -effect is that profilers, debuggers, and system-level tracing tools produce -more complete and more reliable results out of the box. +For Python users and application developers, this change is invisible: no APIs +change, no behaviour changes, and no user action is needed. The only +observable effect is that profilers, debuggers, and system-level tracing tools +produce more complete and more reliable results out of the box. + +Though extensions should see negligible overhead, extension authors who observe a +measurable regression in a specific module can opt out as described in +`Extension Build Impact`_. The ``--without-frame-pointers`` configure flag is +documented in `Opt-Out Configure Flag`_. Reference Implementation From 42c762a037fe967ed5a344da3c54eea82ed71ab5 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 10:41:18 -0700 Subject: [PATCH 03/21] Add ref back --- peps/pep-0830.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index c50cb96d6ee..0fe8ab2729f 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -422,7 +422,8 @@ JIT compilers (V8, LuaJIT, .NET CoreCLR, Julia, LLVM's ORC JIT), which typically require hundreds to thousands of lines of code to implement custom DWARF ``.eh_frame`` generation, GDB JIT interface support (``__jit_debug_register_code``), and per-unwinder registration APIs -(``_U_dyn_register``, ``__register_frame``). +(``_U_dyn_register``, ``__register_frame``). See issue `#126910`_ for +further discussion of frame pointers and the JIT. The Ecosystem Has Already Adopted Frame Pointers ------------------------------------------------ From 2025921d6a5ba53c7eed3ae045bf003289657ac3 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 10:45:53 -0700 Subject: [PATCH 04/21] Fix flame graph --- peps/pep-0830.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 0fe8ab2729f..3bc069780c4 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -201,10 +201,10 @@ processes. The Linux kernel has no DWARF unwinder and, per Linus Torvalds, will not gain one [#torvalds_fp]_; the kernel developed its own ORC format for internal use instead. -The impact extends beyond CPU profiling. Off-CPU flamegraphs (used to +The impact extends beyond CPU profiling. Off-CPU flame graphs (used to diagnose latency caused by I/O waits, lock contention, and scheduling delays) rely on the same ``bpf_get_stackid()`` helper to capture the stack at the point -where a thread blocks. As Brendan Gregg notes, off-CPU flamegraphs "can be +where a thread blocks. As Brendan Gregg notes, off-CPU flame graphs "can be dominated by libc read/write and mutex functions, so without frame pointers end up mostly broken" [#gregg2024]_. For Python services where latency matters more than raw CPU throughput, off-CPU profiling is often the most valuable From 3408a2b16696974a9827fac617c258185b509a43 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 10:51:24 -0700 Subject: [PATCH 05/21] Fixed whitespace --- peps/pep-0830.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 3bc069780c4..7b108d096b9 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -51,9 +51,9 @@ Motivation Python's observability story (profiling, debugging, and system-level tracing) is fundamentally limited by the absence of frame pointers. The core motivation -of this PEP is to make Python observable by default, so that profilers are faster -and more accurate, debuggers are more reliable, and eBPF-based tools are functional -without workarounds. +of this PEP is to make Python observable by default, so that profilers are +faster and more accurate, debuggers are more reliable, and eBPF-based tools +are functional without workarounds. Today, users who want to profile CPython with system tools must rebuild the interpreter with special compiler flags, a step that most users cannot or will @@ -906,8 +906,8 @@ observable effect is that profilers, debuggers, and system-level tracing tools produce more complete and more reliable results out of the box. Though extensions should see negligible overhead, extension authors who observe a -measurable regression in a specific module can opt out as described in -`Extension Build Impact`_. The ``--without-frame-pointers`` configure flag is +measurable regression in a specific module can opt out as described in +`Extension Build Impact`_. The ``--without-frame-pointers`` configure flag is documented in `Opt-Out Configure Flag`_. From 4569c5c93538490aa88b0320f904711b517ce67a Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 10:55:29 -0700 Subject: [PATCH 06/21] Update preamble --- peps/pep-0830.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 7b108d096b9..31a0a8b58d9 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -832,8 +832,8 @@ Performance ----------- Full pyperformance results comparing the frame-pointer build against an -identical build without frame pointers (geometric mean and per-benchmark -range, 108 benchmarks): +identical build without frame pointers (geometric mean across 108 +benchmarks): ===================================== ======================= Machine Geometric mean overhead From 6c3bde4458f447a15ab54af1c04a6caccbfaf831 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 20:09:37 -0700 Subject: [PATCH 07/21] Add RPi and M3 results --- peps/pep-0830.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 31a0a8b58d9..e21baca03ff 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -843,8 +843,8 @@ Intel Xeon Platinum 8480 (x86-64) 1.01x slower AMD EPYC 9654 (x86-64) 1.01x slower AWS Graviton c7g.16xlarge (aarch64) 1.02x slower Ampere Altra Max (aarch64) 1.01x slower -Raspberry Pi (aarch64) +X.X% -macOS M3 (arm64) +X.X% +Raspberry Pi (aarch64, Linux) 1.00x slower +macOS M3 (arm64, macOS) 1.00x slower ===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit From 87a3af7dcc4e06942c682e9cd78871b20405a4e7 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 8 Apr 2026 20:10:50 -0700 Subject: [PATCH 08/21] Clean up table --- peps/pep-0830.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index e21baca03ff..0077d03a1f4 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -838,13 +838,13 @@ benchmarks): ===================================== ======================= Machine Geometric mean overhead ===================================== ======================= -Apple M2 Mac Mini (arm64, macOS) 1.01x slower +Apple M2 Mac Mini (arm64) 1.01x slower Intel Xeon Platinum 8480 (x86-64) 1.01x slower AMD EPYC 9654 (x86-64) 1.01x slower AWS Graviton c7g.16xlarge (aarch64) 1.02x slower Ampere Altra Max (aarch64) 1.01x slower -Raspberry Pi (aarch64, Linux) 1.00x slower -macOS M3 (arm64, macOS) 1.00x slower +Raspberry Pi (aarch64). 1.00x slower +macOS M3 (arm64) 1.00x slower ===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit From 2f241a526fdbcbee658a837fa17acd78be7153d4 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 18:39:30 +0800 Subject: [PATCH 09/21] Add my benchmarks --- peps/pep-0830.rst | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 0077d03a1f4..ba33fb7a35f 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -832,8 +832,10 @@ Performance ----------- Full pyperformance results comparing the frame-pointer build against an -identical build without frame pointers (geometric mean across 108 -benchmarks): +identical build without frame pointers (geometric mean across 80 +benchmarks [#missing_benchmarks]_). For reproducibility, +pyperformance JSON files can be found in +[#benchmarks]_. Benchmark visualization can be found in the Appendix: ===================================== ======================= Machine Geometric mean overhead @@ -844,7 +846,8 @@ AMD EPYC 9654 (x86-64) 1.01x slower AWS Graviton c7g.16xlarge (aarch64) 1.02x slower Ampere Altra Max (aarch64) 1.01x slower Raspberry Pi (aarch64). 1.00x slower -macOS M3 (arm64) 1.00x slower +macOS M3 Pro (arm64) 1.00x slower +Intel i7 12700H (x86-64) 1.02x slower ===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit @@ -1031,11 +1034,22 @@ Footnotes and Linux", by Markus Stange. https://github.com/mstange/samply +.. [#benchmarks] Python frame-pointer benchmark pyperformance JSON files + https://github.com/Fidget-Spinner/python-framepointer-bench + +.. [#missing_benchmarks] Some benchmarks are missing due to incompatibilities with + Python 3.15alpha. + .. _#96174: https://github.com/python/cpython/issues/96174 .. _python/cpython issue #96174: https://github.com/python/cpython/issues/96174 .. _#126910: https://github.com/python/cpython/issues/126910 +Appendix +======== + +# TODO: KJ, once we have Diego's results. + Copyright ========= From 941880e1b561d09d67a524b07e499aadc1be4bcc Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 22:15:47 +0800 Subject: [PATCH 10/21] Add perf figures, tighten JIT claims --- peps/pep-0830.rst | 38 +- peps/pep-830_perf_over_baseline.svg | 1980 + peps/pep-830_perf_over_baseline_indiv.svg | 40250 ++++++++++++++++++++ 3 files changed, 42255 insertions(+), 13 deletions(-) create mode 100644 peps/pep-830_perf_over_baseline.svg create mode 100644 peps/pep-830_perf_over_baseline_indiv.svg diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index ba33fb7a35f..914e3a3fee7 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -405,7 +405,7 @@ The JIT Compiler Needs Frame Pointers to Be Debuggable ------------------------------------------------------ CPython's copy-and-patch JIT (:pep:`744`) generates native machine code at -runtime. Without frame pointers in the interpreter, stack unwinding through +runtime. Without reserved frame pointers in the JIT code, stack unwinding through JIT frames is broken for virtually every tool in the ecosystem: GDB, LLDB, libunwind, libdw (elfutils), py-spy, Austin, pystack, memray, ``perf``, and all eBPF-based profilers. Ensuring full-stack observability for JIT-compiled @@ -413,10 +413,10 @@ code is a prerequisite for the JIT to be considered production-ready. Individual JIT stencils do not need frame-pointer prologues; the entire JIT region can be treated as a single frameless region for unwinding purposes. -What matters is that the interpreter itself is built with frame pointers, so +What matters is that the JIT itself is must reserve frame pointers, so that the frame-pointer register (``%rbp`` on x86-64, ``x29`` on AArch64) is reserved and not clobbered by stencil code. With frame pointers in the -interpreter, unwinders can walk through JIT regions without needing to inspect +JIT, most unwinders can walk through JIT regions without needing to inspect individual stencils. This is a remarkably good outcome compared to other JIT compilers (V8, LuaJIT, .NET CoreCLR, Julia, LLVM's ORC JIT), which typically require hundreds to thousands of lines of code to implement custom @@ -432,7 +432,7 @@ The shift toward frame pointers has already happened independently of CPython upstream, and at massive scale. ``python-build-standalone``, the hermetic Python distribution used by ``uv``, -``mise``, ``rye``, and many CI systems, enabled ``-fno-omit-frame-pointer`` on +``mise``, ``rye``, and many CI systems, enfabled ``-fno-omit-frame-pointer`` on all x86-64 and AArch64 Linux builds in early 2026 and shipped in ``uv`` 0.11.0 [#pbs992]_. Gregory Szorc, the project's creator, stated: "Frame pointers should be enabled on 100% of x86-64 / aarch64 binaries in 2026. Full stop." He @@ -840,14 +840,14 @@ pyperformance JSON files can be found in ===================================== ======================= Machine Geometric mean overhead ===================================== ======================= -Apple M2 Mac Mini (arm64) 1.01x slower -Intel Xeon Platinum 8480 (x86-64) 1.01x slower -AMD EPYC 9654 (x86-64) 1.01x slower -AWS Graviton c7g.16xlarge (aarch64) 1.02x slower -Ampere Altra Max (aarch64) 1.01x slower -Raspberry Pi (aarch64). 1.00x slower -macOS M3 Pro (arm64) 1.00x slower -Intel i7 12700H (x86-64) 1.02x slower +Apple M2 Mac Mini (arm64) 1.006x slower +macOS M3 Pro (arm64) 1.001x slower +Raspberry Pi (aarch64). 1.002x slower +Ampere Altra Max (aarch64) 1.020x slower +AWS Graviton c7g.16xlarge (aarch64) 1.027x slower +Intel i7 12700H (x86-64) 1.019x slower +AMD EPYC 9654 (x86-64) 1.008x slower +Intel Xeon Platinum 8480 (x86-64) 1.006x slower ===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit @@ -1048,7 +1048,19 @@ Footnotes Appendix ======== -# TODO: KJ, once we have Diego's results. +For all graphs below, the green dots are geometric means of the +individual benchmark's median, while orange lines are the median of our data points. + +The first graph is the overall effect on pyperformance seen on each system. +Apart from the Ubuntu AWS Graviton System, all system configurations have below 2% +geometric mean and median slowdown: + +.. image:: pep-830_perf_over_baseline.svg + +For individual benchmark results, see the following: + +.. image:: pep-830_perf_over_baseline_indiv.svg + Copyright ========= diff --git a/peps/pep-830_perf_over_baseline.svg b/peps/pep-830_perf_over_baseline.svg new file mode 100644 index 00000000000..9f91fc3655c --- /dev/null +++ b/peps/pep-830_perf_over_baseline.svg @@ -0,0 +1,1980 @@ + + + + + + + + 2026-04-09T21:50:42.049702 + image/svg+xml + + + Matplotlib v3.10.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/peps/pep-830_perf_over_baseline_indiv.svg b/peps/pep-830_perf_over_baseline_indiv.svg new file mode 100644 index 00000000000..85082635c6c --- /dev/null +++ b/peps/pep-830_perf_over_baseline_indiv.svg @@ -0,0 +1,40250 @@ + + + + + + + + 2026-04-09T21:55:00.790820 + image/svg+xml + + + Matplotlib v3.10.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 009204a9977adc04210ef53ce36de942b6288333 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 22:18:07 +0800 Subject: [PATCH 11/21] remove Diego (for now) --- peps/pep-0830.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 914e3a3fee7..313208009aa 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -3,7 +3,6 @@ Title: Frame Pointers Everywhere: Enabling System-Level Observability for Python Author: Pablo Galindo Salgado , Ken Jin , Savannah Ostrowski , - Diego Russo Discussions-To: Status: Draft Type: Standards Track From bd948d0982f9104a0872c62bd97f873dde416838 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 23:36:46 +0800 Subject: [PATCH 12/21] fix typo --- peps/pep-0830.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 313208009aa..70770269b62 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -431,7 +431,7 @@ The shift toward frame pointers has already happened independently of CPython upstream, and at massive scale. ``python-build-standalone``, the hermetic Python distribution used by ``uv``, -``mise``, ``rye``, and many CI systems, enfabled ``-fno-omit-frame-pointer`` on +``mise``, ``rye``, and many CI systems, enabled ``-fno-omit-frame-pointer`` on all x86-64 and AArch64 Linux builds in early 2026 and shipped in ``uv`` 0.11.0 [#pbs992]_. Gregory Szorc, the project's creator, stated: "Frame pointers should be enabled on 100% of x86-64 / aarch64 binaries in 2026. Full stop." He From 02c94e60beda45675de0a4c4b52e99407de0302e Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 23:43:23 +0800 Subject: [PATCH 13/21] Show outliers --- peps/pep-0830.rst | 4 +- ...ne.svg => pep-0830_perf_over_baseline.svg} | 801 ++++++++++-------- ... => pep-0830_perf_over_baseline_indiv.svg} | 0 3 files changed, 460 insertions(+), 345 deletions(-) rename peps/{pep-830_perf_over_baseline.svg => pep-0830_perf_over_baseline.svg} (72%) rename peps/{pep-830_perf_over_baseline_indiv.svg => pep-0830_perf_over_baseline_indiv.svg} (100%) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index 70770269b62..c4dfd796f9e 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -1054,11 +1054,11 @@ The first graph is the overall effect on pyperformance seen on each system. Apart from the Ubuntu AWS Graviton System, all system configurations have below 2% geometric mean and median slowdown: -.. image:: pep-830_perf_over_baseline.svg +.. image:: pep-0830_perf_over_baseline.svg For individual benchmark results, see the following: -.. image:: pep-830_perf_over_baseline_indiv.svg +.. image:: pep-0830_perf_over_baseline_indiv.svg Copyright diff --git a/peps/pep-830_perf_over_baseline.svg b/peps/pep-0830_perf_over_baseline.svg similarity index 72% rename from peps/pep-830_perf_over_baseline.svg rename to peps/pep-0830_perf_over_baseline.svg index 9f91fc3655c..afc1700f047 100644 --- a/peps/pep-830_perf_over_baseline.svg +++ b/peps/pep-0830_perf_over_baseline.svg @@ -6,7 +6,7 @@ - 2026-04-09T21:50:42.049702 + 2026-04-09T23:41:26.447009 image/svg+xml @@ -32,8 +32,8 @@ z @@ -41,17 +41,17 @@ z +L 79.540933 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -250,12 +250,12 @@ z +L 129.975443 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -371,12 +371,12 @@ z +L 180.409953 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -556,12 +556,12 @@ z +L 230.844464 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -722,12 +722,12 @@ z +L 281.278974 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -919,12 +919,12 @@ z +L 331.713484 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1010,12 +1010,12 @@ z +L 382.147995 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1146,12 +1146,12 @@ z +L 432.582505 6.47595 +" clip-path="url(#pc43c3a8cdf)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1348,23 +1348,23 @@ z - + - - + - - + + - + - + - + - - + + - + - + - + - + @@ -1436,18 +1436,18 @@ L 457.79976 114.520064 - + - + - + @@ -1458,18 +1458,18 @@ L 457.79976 80.566553 - + - + - + @@ -1480,29 +1480,73 @@ L 457.79976 46.613042 - + - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1530,359 +1574,430 @@ L 457.79976 12.659531 - - - - - - - - - - - - - - - - +" clip-path="url(#pc43c3a8cdf)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - - + - + + + + + + + + + + + + + + + + + + + - + - + - - - - + - + - + + + + + + + - + - - - - + - + - + - - - - + + + - - + +" clip-path="url(#pc43c3a8cdf)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + - + - + - + - + + + + + + + - - + +" clip-path="url(#pc43c3a8cdf)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - - + - + + + + + + + - + - + - + - - - - - - - + - - - + + + + + + - - - - + - - - - + - - - - + - - - - + - - - + + + + + + - - - - + - + - + - + - + + + - + + + + + + + - + + + + - + + + + - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1891,35 +2006,35 @@ L 457.79976 189.851766 " style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> - - - - + - + - - + - + @@ -1973,8 +2088,8 @@ z - - + + diff --git a/peps/pep-830_perf_over_baseline_indiv.svg b/peps/pep-0830_perf_over_baseline_indiv.svg similarity index 100% rename from peps/pep-830_perf_over_baseline_indiv.svg rename to peps/pep-0830_perf_over_baseline_indiv.svg From 1c194952b1adcb6bffda70152785a2d8a38db99a Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 9 Apr 2026 23:45:21 +0800 Subject: [PATCH 14/21] Update pep-0830.rst --- peps/pep-0830.rst | 1 + peps/pep-0830_perf_over_baseline.svg | 2230 +- peps/pep-0830_perf_over_baseline_indiv.svg | 26594 +++++++++---------- 3 files changed, 14413 insertions(+), 14412 deletions(-) diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index c4dfd796f9e..ff80891f88b 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -1049,6 +1049,7 @@ Appendix For all graphs below, the green dots are geometric means of the individual benchmark's median, while orange lines are the median of our data points. +Hollow circles reperesent outliers. The first graph is the overall effect on pyperformance seen on each system. Apart from the Ubuntu AWS Graviton System, all system configurations have below 2% diff --git a/peps/pep-0830_perf_over_baseline.svg b/peps/pep-0830_perf_over_baseline.svg index afc1700f047..7e098a25398 100644 --- a/peps/pep-0830_perf_over_baseline.svg +++ b/peps/pep-0830_perf_over_baseline.svg @@ -21,33 +21,33 @@ - - - - @@ -58,181 +58,181 @@ L 0 3.5 - - - - - - - @@ -249,8 +249,8 @@ z - @@ -262,95 +262,95 @@ L 129.975443 6.47595 - - - - @@ -370,8 +370,8 @@ z - @@ -383,159 +383,159 @@ L 180.409953 6.47595 - - - - - - - @@ -555,8 +555,8 @@ z - @@ -568,128 +568,128 @@ L 230.844464 6.47595 - - - - - - - @@ -721,8 +721,8 @@ z - @@ -734,150 +734,150 @@ L 281.278974 6.47595 - - - - - - - - @@ -918,8 +918,8 @@ z - @@ -931,54 +931,54 @@ L 331.713484 6.47595 - - - - @@ -1009,8 +1009,8 @@ z - @@ -1022,101 +1022,101 @@ L 382.147995 6.47595 - - - - - @@ -1145,8 +1145,8 @@ z - @@ -1158,58 +1158,58 @@ L 432.582505 6.47595 - - @@ -1251,73 +1251,73 @@ z - - - @@ -1348,14 +1348,14 @@ z - - @@ -1366,19 +1366,19 @@ L -3.5 0 - @@ -1392,8 +1392,8 @@ z - @@ -1414,8 +1414,8 @@ L 457.79976 151.292846 - @@ -1436,8 +1436,8 @@ L 457.79976 127.210572 - @@ -1458,8 +1458,8 @@ L 457.79976 103.128298 - @@ -1480,8 +1480,8 @@ L 457.79976 79.046024 - @@ -1502,8 +1502,8 @@ L 457.79976 54.96375 - @@ -1524,8 +1524,8 @@ L 457.79976 30.881476 - @@ -1574,45 +1574,45 @@ L 457.79976 6.799202 - - - - - - @@ -1631,32 +1631,32 @@ z - - - - - @@ -1666,32 +1666,32 @@ L 136.279757 89.287599 - - - - - @@ -1700,32 +1700,32 @@ L 186.714267 77.548095 - - - - - @@ -1738,32 +1738,32 @@ L 237.148777 90.540383 - - - - - @@ -1773,32 +1773,32 @@ L 287.583288 101.309776 - - - - - @@ -1808,32 +1808,32 @@ L 338.017798 80.354412 - - - - - @@ -1843,32 +1843,32 @@ L 388.452308 63.935028 - - - - - @@ -1877,18 +1877,18 @@ L 438.886819 70.53072 - - @@ -1897,138 +1897,138 @@ z - - - - - - - - - - - - - - - - - - - - - - @@ -2036,23 +2036,23 @@ z - @@ -2066,10 +2066,10 @@ z - diff --git a/peps/pep-0830_perf_over_baseline_indiv.svg b/peps/pep-0830_perf_over_baseline_indiv.svg index 85082635c6c..a0f67ba162a 100644 --- a/peps/pep-0830_perf_over_baseline_indiv.svg +++ b/peps/pep-0830_perf_over_baseline_indiv.svg @@ -21,33 +21,33 @@ - - - - @@ -57,8 +57,8 @@ L 0 3.5 - @@ -69,8 +69,8 @@ L 87.624531 3.00024 - @@ -81,8 +81,8 @@ L 107.20103 3.00024 - @@ -93,8 +93,8 @@ L 126.777529 3.00024 - @@ -105,8 +105,8 @@ L 146.354028 3.00024 - @@ -117,8 +117,8 @@ L 165.930527 3.00024 - @@ -129,8 +129,8 @@ L 185.507026 3.00024 - @@ -143,102 +143,102 @@ L 205.083525 3.00024 - - - - @@ -252,14 +252,14 @@ z - - @@ -270,61 +270,61 @@ L -3.5 0 - - - - @@ -338,8 +338,8 @@ z - @@ -360,312 +360,312 @@ L 214.871775 7.213396 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -676,8 +676,8 @@ L 268.305817 3.00024 - @@ -688,8 +688,8 @@ L 287.882316 3.00024 - @@ -700,8 +700,8 @@ L 307.458815 3.00024 - @@ -712,8 +712,8 @@ L 327.035314 3.00024 - @@ -724,8 +724,8 @@ L 346.611813 3.00024 - @@ -736,8 +736,8 @@ L 366.188312 3.00024 - @@ -748,8 +748,8 @@ L 385.764811 3.00024 - @@ -762,208 +762,208 @@ L 405.34131 3.00024 - - - - - - - - - @@ -989,8 +989,8 @@ z - @@ -1002,43 +1002,43 @@ L 415.129559 77.171933 - @@ -1052,8 +1052,8 @@ z - @@ -1074,8 +1074,8 @@ L 415.129559 43.41197 - @@ -1096,312 +1096,312 @@ L 415.129559 9.652006 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1412,8 +1412,8 @@ L 468.563601 3.00024 - @@ -1424,8 +1424,8 @@ L 488.1401 3.00024 - @@ -1436,8 +1436,8 @@ L 507.716599 3.00024 - @@ -1448,8 +1448,8 @@ L 527.293098 3.00024 - @@ -1460,8 +1460,8 @@ L 546.869597 3.00024 - @@ -1472,8 +1472,8 @@ L 566.446096 3.00024 - @@ -1484,8 +1484,8 @@ L 586.022595 3.00024 - @@ -1498,136 +1498,136 @@ L 605.599094 3.00024 - - - - - - @@ -1660,8 +1660,8 @@ z - @@ -1682,8 +1682,8 @@ L 615.387344 74.310064 - @@ -1704,8 +1704,8 @@ L 615.387344 43.356462 - @@ -1726,312 +1726,312 @@ L 615.387344 12.402859 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2042,8 +2042,8 @@ L 668.821386 3.00024 - @@ -2054,8 +2054,8 @@ L 688.397885 3.00024 - @@ -2066,8 +2066,8 @@ L 707.974384 3.00024 - @@ -2078,8 +2078,8 @@ L 727.550883 3.00024 - @@ -2090,8 +2090,8 @@ L 747.127382 3.00024 - @@ -2102,8 +2102,8 @@ L 766.703881 3.00024 - @@ -2114,8 +2114,8 @@ L 786.28038 3.00024 - @@ -2159,8 +2159,8 @@ L 805.856879 3.00024 - @@ -2172,34 +2172,34 @@ L 815.645128 61.893612 - @@ -2213,8 +2213,8 @@ z - @@ -2235,8 +2235,8 @@ L 815.645128 41.683085 - @@ -2257,312 +2257,312 @@ L 815.645128 21.472558 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2573,8 +2573,8 @@ L 869.07917 3.00024 - @@ -2585,8 +2585,8 @@ L 888.655669 3.00024 - @@ -2597,8 +2597,8 @@ L 908.232168 3.00024 - @@ -2609,8 +2609,8 @@ L 927.808667 3.00024 - @@ -2621,8 +2621,8 @@ L 947.385166 3.00024 - @@ -2633,8 +2633,8 @@ L 966.961665 3.00024 - @@ -2645,8 +2645,8 @@ L 986.538164 3.00024 - @@ -2677,8 +2677,8 @@ L 1006.114663 3.00024 - @@ -2690,39 +2690,39 @@ L 1015.902913 68.622186 - - @@ -2736,8 +2736,8 @@ z - @@ -2758,8 +2758,8 @@ L 1015.902913 44.826325 - @@ -2780,312 +2780,312 @@ L 1015.902913 21.030463 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3096,8 +3096,8 @@ L 1069.336955 3.00024 - @@ -3108,8 +3108,8 @@ L 1088.913454 3.00024 - @@ -3120,8 +3120,8 @@ L 1108.489953 3.00024 - @@ -3132,8 +3132,8 @@ L 1128.066452 3.00024 - @@ -3144,8 +3144,8 @@ L 1147.642951 3.00024 - @@ -3156,8 +3156,8 @@ L 1167.21945 3.00024 - @@ -3168,8 +3168,8 @@ L 1186.795949 3.00024 - @@ -3203,8 +3203,8 @@ L 1206.372448 3.00024 - @@ -3225,8 +3225,8 @@ L 1216.160697 72.696506 - @@ -3247,8 +3247,8 @@ L 1216.160697 42.172905 - @@ -3269,312 +3269,312 @@ L 1216.160697 11.649304 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3585,8 +3585,8 @@ L 68.048032 104.162832 - @@ -3597,8 +3597,8 @@ L 87.624531 104.162832 - @@ -3609,8 +3609,8 @@ L 107.20103 104.162832 - @@ -3621,8 +3621,8 @@ L 126.777529 104.162832 - @@ -3633,8 +3633,8 @@ L 146.354028 104.162832 - @@ -3645,8 +3645,8 @@ L 165.930527 104.162832 - @@ -3657,8 +3657,8 @@ L 185.507026 104.162832 - @@ -3671,17 +3671,17 @@ L 205.083525 104.162832 - @@ -3713,8 +3713,8 @@ z - @@ -3735,8 +3735,8 @@ L 214.871775 175.270847 - @@ -3757,8 +3757,8 @@ L 214.871775 144.850938 - @@ -3779,312 +3779,312 @@ L 214.871775 114.431029 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4095,8 +4095,8 @@ L 268.305817 104.162832 - @@ -4107,8 +4107,8 @@ L 287.882316 104.162832 - @@ -4119,8 +4119,8 @@ L 307.458815 104.162832 - @@ -4131,8 +4131,8 @@ L 327.035314 104.162832 - @@ -4143,8 +4143,8 @@ L 346.611813 104.162832 - @@ -4155,8 +4155,8 @@ L 366.188312 104.162832 - @@ -4167,8 +4167,8 @@ L 385.764811 104.162832 - @@ -4211,8 +4211,8 @@ L 405.34131 104.162832 - @@ -4233,8 +4233,8 @@ L 415.129559 175.285671 - @@ -4255,8 +4255,8 @@ L 415.129559 146.52958 - @@ -4277,312 +4277,312 @@ L 415.129559 117.773489 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4593,8 +4593,8 @@ L 468.563601 104.162832 - @@ -4605,8 +4605,8 @@ L 488.1401 104.162832 - @@ -4617,8 +4617,8 @@ L 507.716599 104.162832 - @@ -4629,8 +4629,8 @@ L 527.293098 104.162832 - @@ -4641,8 +4641,8 @@ L 546.869597 104.162832 - @@ -4653,8 +4653,8 @@ L 566.446096 104.162832 - @@ -4665,8 +4665,8 @@ L 586.022595 104.162832 - @@ -4699,8 +4699,8 @@ L 605.599094 104.162832 - @@ -4721,8 +4721,8 @@ L 615.387344 176.240524 - @@ -4743,8 +4743,8 @@ L 615.387344 145.381651 - @@ -4765,312 +4765,312 @@ L 615.387344 114.522777 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5081,8 +5081,8 @@ L 668.821386 104.162832 - @@ -5093,8 +5093,8 @@ L 688.397885 104.162832 - @@ -5105,8 +5105,8 @@ L 707.974384 104.162832 - @@ -5117,8 +5117,8 @@ L 727.550883 104.162832 - @@ -5129,8 +5129,8 @@ L 747.127382 104.162832 - @@ -5141,8 +5141,8 @@ L 766.703881 104.162832 - @@ -5153,8 +5153,8 @@ L 786.28038 104.162832 - @@ -5190,8 +5190,8 @@ L 805.856879 104.162832 - @@ -5212,8 +5212,8 @@ L 815.645128 147.350268 - @@ -5234,312 +5234,312 @@ L 815.645128 104.563972 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5550,8 +5550,8 @@ L 869.07917 104.162832 - @@ -5562,8 +5562,8 @@ L 888.655669 104.162832 - @@ -5574,8 +5574,8 @@ L 908.232168 104.162832 - @@ -5586,8 +5586,8 @@ L 927.808667 104.162832 - @@ -5598,8 +5598,8 @@ L 947.385166 104.162832 - @@ -5610,8 +5610,8 @@ L 966.961665 104.162832 - @@ -5622,8 +5622,8 @@ L 986.538164 104.162832 - @@ -5636,60 +5636,60 @@ L 1006.114663 104.162832 - - - @@ -5717,8 +5717,8 @@ z - @@ -5739,8 +5739,8 @@ L 1015.902913 144.86653 - @@ -5761,312 +5761,312 @@ L 1015.902913 109.143705 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6077,8 +6077,8 @@ L 1069.336955 104.162832 - @@ -6089,8 +6089,8 @@ L 1088.913454 104.162832 - @@ -6101,8 +6101,8 @@ L 1108.489953 104.162832 - @@ -6113,8 +6113,8 @@ L 1128.066452 104.162832 - @@ -6125,8 +6125,8 @@ L 1147.642951 104.162832 - @@ -6137,8 +6137,8 @@ L 1167.21945 104.162832 - @@ -6149,8 +6149,8 @@ L 1186.795949 104.162832 - @@ -6181,8 +6181,8 @@ L 1206.372448 104.162832 - @@ -6203,8 +6203,8 @@ L 1216.160697 170.408368 - @@ -6225,8 +6225,8 @@ L 1216.160697 137.596004 - @@ -6247,312 +6247,312 @@ L 1216.160697 104.78364 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6563,8 +6563,8 @@ L 68.048032 204.967916 - @@ -6575,8 +6575,8 @@ L 87.624531 204.967916 - @@ -6587,8 +6587,8 @@ L 107.20103 204.967916 - @@ -6599,8 +6599,8 @@ L 126.777529 204.967916 - @@ -6611,8 +6611,8 @@ L 146.354028 204.967916 - @@ -6623,8 +6623,8 @@ L 165.930527 204.967916 - @@ -6635,8 +6635,8 @@ L 185.507026 204.967916 - @@ -6649,30 +6649,30 @@ L 205.083525 204.967916 - - @@ -6691,8 +6691,8 @@ z - @@ -6713,8 +6713,8 @@ L 214.871775 243.740616 - @@ -6735,312 +6735,312 @@ L 214.871775 207.972769 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7051,8 +7051,8 @@ L 268.305817 204.967916 - @@ -7063,8 +7063,8 @@ L 287.882316 204.967916 - @@ -7075,8 +7075,8 @@ L 307.458815 204.967916 - @@ -7087,8 +7087,8 @@ L 327.035314 204.967916 - @@ -7099,8 +7099,8 @@ L 346.611813 204.967916 - @@ -7111,8 +7111,8 @@ L 366.188312 204.967916 - @@ -7123,8 +7123,8 @@ L 385.764811 204.967916 - @@ -7147,8 +7147,8 @@ L 405.34131 204.967916 - @@ -7169,8 +7169,8 @@ L 415.129559 260.481363 - @@ -7191,8 +7191,8 @@ L 415.129559 241.287733 - @@ -7213,312 +7213,312 @@ L 415.129559 222.094102 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7529,8 +7529,8 @@ L 468.563601 204.967916 - @@ -7541,8 +7541,8 @@ L 488.1401 204.967916 - @@ -7553,8 +7553,8 @@ L 507.716599 204.967916 - @@ -7565,8 +7565,8 @@ L 527.293098 204.967916 - @@ -7577,8 +7577,8 @@ L 546.869597 204.967916 - @@ -7589,8 +7589,8 @@ L 566.446096 204.967916 - @@ -7601,8 +7601,8 @@ L 586.022595 204.967916 - @@ -7634,8 +7634,8 @@ L 605.599094 204.967916 - @@ -7656,8 +7656,8 @@ L 615.387344 268.009917 - @@ -7678,8 +7678,8 @@ L 615.387344 245.376846 - @@ -7700,312 +7700,312 @@ L 615.387344 222.743776 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8016,8 +8016,8 @@ L 668.821386 204.967916 - @@ -8028,8 +8028,8 @@ L 688.397885 204.967916 - @@ -8040,8 +8040,8 @@ L 707.974384 204.967916 - @@ -8052,8 +8052,8 @@ L 727.550883 204.967916 - @@ -8064,8 +8064,8 @@ L 747.127382 204.967916 - @@ -8076,8 +8076,8 @@ L 766.703881 204.967916 - @@ -8088,8 +8088,8 @@ L 786.28038 204.967916 - @@ -8117,8 +8117,8 @@ L 805.856879 204.967916 - @@ -8139,8 +8139,8 @@ L 815.645128 269.985671 - @@ -8161,8 +8161,8 @@ L 815.645128 244.294062 - @@ -8183,312 +8183,312 @@ L 815.645128 218.602454 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8499,8 +8499,8 @@ L 869.07917 204.967916 - @@ -8511,8 +8511,8 @@ L 888.655669 204.967916 - @@ -8523,8 +8523,8 @@ L 908.232168 204.967916 - @@ -8535,8 +8535,8 @@ L 927.808667 204.967916 - @@ -8547,8 +8547,8 @@ L 947.385166 204.967916 - @@ -8559,8 +8559,8 @@ L 966.961665 204.967916 - @@ -8571,8 +8571,8 @@ L 986.538164 204.967916 - @@ -8606,8 +8606,8 @@ L 1006.114663 204.967916 - @@ -8628,8 +8628,8 @@ L 1015.902913 277.113679 - @@ -8650,8 +8650,8 @@ L 1015.902913 241.990957 - @@ -8672,312 +8672,312 @@ L 1015.902913 206.868235 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8988,8 +8988,8 @@ L 1069.336955 204.967916 - @@ -9000,8 +9000,8 @@ L 1088.913454 204.967916 - @@ -9012,8 +9012,8 @@ L 1108.489953 204.967916 - @@ -9024,8 +9024,8 @@ L 1128.066452 204.967916 - @@ -9036,8 +9036,8 @@ L 1147.642951 204.967916 - @@ -9048,8 +9048,8 @@ L 1167.21945 204.967916 - @@ -9060,8 +9060,8 @@ L 1186.795949 204.967916 - @@ -9091,8 +9091,8 @@ L 1206.372448 204.967916 - @@ -9113,8 +9113,8 @@ L 1216.160697 278.298952 - @@ -9135,8 +9135,8 @@ L 1216.160697 242.012778 - @@ -9157,312 +9157,312 @@ L 1216.160697 205.726604 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9473,8 +9473,8 @@ L 68.048032 305.524955 - @@ -9485,8 +9485,8 @@ L 87.624531 305.524955 - @@ -9497,8 +9497,8 @@ L 107.20103 305.524955 - @@ -9509,8 +9509,8 @@ L 126.777529 305.524955 - @@ -9521,8 +9521,8 @@ L 146.354028 305.524955 - @@ -9533,8 +9533,8 @@ L 165.930527 305.524955 - @@ -9545,8 +9545,8 @@ L 185.507026 305.524955 - @@ -9572,8 +9572,8 @@ L 205.083525 305.524955 - @@ -9594,8 +9594,8 @@ L 214.871775 378.998614 - @@ -9616,312 +9616,312 @@ L 214.871775 342.131 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9932,8 +9932,8 @@ L 268.305817 305.524955 - @@ -9944,8 +9944,8 @@ L 287.882316 305.524955 - @@ -9956,8 +9956,8 @@ L 307.458815 305.524955 - @@ -9968,8 +9968,8 @@ L 327.035314 305.524955 - @@ -9980,8 +9980,8 @@ L 346.611813 305.524955 - @@ -9992,8 +9992,8 @@ L 366.188312 305.524955 - @@ -10004,8 +10004,8 @@ L 385.764811 305.524955 - @@ -10036,8 +10036,8 @@ L 405.34131 305.524955 - @@ -10058,8 +10058,8 @@ L 415.129559 362.000832 - @@ -10080,8 +10080,8 @@ L 415.129559 343.118089 - @@ -10102,312 +10102,312 @@ L 415.129559 324.235347 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -10418,8 +10418,8 @@ L 468.563601 305.524955 - @@ -10430,8 +10430,8 @@ L 488.1401 305.524955 - @@ -10442,8 +10442,8 @@ L 507.716599 305.524955 - @@ -10454,8 +10454,8 @@ L 527.293098 305.524955 - @@ -10466,8 +10466,8 @@ L 546.869597 305.524955 - @@ -10478,8 +10478,8 @@ L 566.446096 305.524955 - @@ -10490,8 +10490,8 @@ L 586.022595 305.524955 - @@ -10524,8 +10524,8 @@ L 605.599094 305.524955 - @@ -10546,8 +10546,8 @@ L 615.387344 378.727289 - @@ -10568,312 +10568,312 @@ L 615.387344 341.477643 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -10884,8 +10884,8 @@ L 668.821386 305.524955 - @@ -10896,8 +10896,8 @@ L 688.397885 305.524955 - @@ -10908,8 +10908,8 @@ L 707.974384 305.524955 - @@ -10920,8 +10920,8 @@ L 727.550883 305.524955 - @@ -10932,8 +10932,8 @@ L 747.127382 305.524955 - @@ -10944,8 +10944,8 @@ L 766.703881 305.524955 - @@ -10956,8 +10956,8 @@ L 786.28038 305.524955 - @@ -10984,8 +10984,8 @@ L 805.856879 305.524955 - @@ -11006,8 +11006,8 @@ L 815.645128 343.333845 - @@ -11028,312 +11028,312 @@ L 815.645128 306.531717 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11344,8 +11344,8 @@ L 869.07917 305.524955 - @@ -11356,8 +11356,8 @@ L 888.655669 305.524955 - @@ -11368,8 +11368,8 @@ L 908.232168 305.524955 - @@ -11380,8 +11380,8 @@ L 927.808667 305.524955 - @@ -11392,8 +11392,8 @@ L 947.385166 305.524955 - @@ -11404,8 +11404,8 @@ L 966.961665 305.524955 - @@ -11416,8 +11416,8 @@ L 986.538164 305.524955 - @@ -11443,8 +11443,8 @@ L 1006.114663 305.524955 - @@ -11465,8 +11465,8 @@ L 1015.902913 372.235105 - @@ -11487,8 +11487,8 @@ L 1015.902913 344.054112 - @@ -11509,312 +11509,312 @@ L 1015.902913 315.873118 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11825,8 +11825,8 @@ L 1069.336955 305.524955 - @@ -11837,8 +11837,8 @@ L 1088.913454 305.524955 - @@ -11849,8 +11849,8 @@ L 1108.489953 305.524955 - @@ -11861,8 +11861,8 @@ L 1128.066452 305.524955 - @@ -11873,8 +11873,8 @@ L 1147.642951 305.524955 - @@ -11885,8 +11885,8 @@ L 1167.21945 305.524955 - @@ -11897,8 +11897,8 @@ L 1186.795949 305.524955 - @@ -11927,8 +11927,8 @@ L 1206.372448 305.524955 - @@ -11949,8 +11949,8 @@ L 1216.160697 361.859431 - @@ -11971,8 +11971,8 @@ L 1216.160697 341.752015 - @@ -11993,312 +11993,312 @@ L 1216.160697 321.644599 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -12309,8 +12309,8 @@ L 68.048032 403.289422 - @@ -12321,8 +12321,8 @@ L 87.624531 403.289422 - @@ -12333,8 +12333,8 @@ L 107.20103 403.289422 - @@ -12345,8 +12345,8 @@ L 126.777529 403.289422 - @@ -12357,8 +12357,8 @@ L 146.354028 403.289422 - @@ -12369,8 +12369,8 @@ L 165.930527 403.289422 - @@ -12381,8 +12381,8 @@ L 185.507026 403.289422 - @@ -12395,25 +12395,25 @@ L 205.083525 403.289422 - @@ -12431,8 +12431,8 @@ z - @@ -12453,8 +12453,8 @@ L 214.871775 462.035844 - @@ -12475,8 +12475,8 @@ L 214.871775 442.305118 - @@ -12497,312 +12497,312 @@ L 214.871775 422.574393 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -12813,8 +12813,8 @@ L 268.305817 403.289422 - @@ -12825,8 +12825,8 @@ L 287.882316 403.289422 - @@ -12837,8 +12837,8 @@ L 307.458815 403.289422 - @@ -12849,8 +12849,8 @@ L 327.035314 403.289422 - @@ -12861,8 +12861,8 @@ L 346.611813 403.289422 - @@ -12873,8 +12873,8 @@ L 366.188312 403.289422 - @@ -12885,8 +12885,8 @@ L 385.764811 403.289422 - @@ -12909,8 +12909,8 @@ L 405.34131 403.289422 - @@ -12931,8 +12931,8 @@ L 415.129559 468.509948 - @@ -12953,8 +12953,8 @@ L 415.129559 438.44403 - @@ -12975,312 +12975,312 @@ L 415.129559 408.378111 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -13291,8 +13291,8 @@ L 468.563601 403.289422 - @@ -13303,8 +13303,8 @@ L 488.1401 403.289422 - @@ -13315,8 +13315,8 @@ L 507.716599 403.289422 - @@ -13327,8 +13327,8 @@ L 527.293098 403.289422 - @@ -13339,8 +13339,8 @@ L 546.869597 403.289422 - @@ -13351,8 +13351,8 @@ L 566.446096 403.289422 - @@ -13363,8 +13363,8 @@ L 586.022595 403.289422 - @@ -13392,8 +13392,8 @@ L 605.599094 403.289422 - @@ -13414,8 +13414,8 @@ L 615.387344 473.769116 - @@ -13436,8 +13436,8 @@ L 615.387344 441.410623 - @@ -13458,312 +13458,312 @@ L 615.387344 409.052129 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -13774,8 +13774,8 @@ L 668.821386 403.289422 - @@ -13786,8 +13786,8 @@ L 688.397885 403.289422 - @@ -13798,8 +13798,8 @@ L 707.974384 403.289422 - @@ -13810,8 +13810,8 @@ L 727.550883 403.289422 - @@ -13822,8 +13822,8 @@ L 747.127382 403.289422 - @@ -13834,8 +13834,8 @@ L 766.703881 403.289422 - @@ -13846,8 +13846,8 @@ L 786.28038 403.289422 - @@ -13876,8 +13876,8 @@ L 805.856879 403.289422 - @@ -13898,8 +13898,8 @@ L 815.645128 466.395515 - @@ -13920,8 +13920,8 @@ L 815.645128 444.547003 - @@ -13942,312 +13942,312 @@ L 815.645128 422.698491 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -14258,8 +14258,8 @@ L 869.07917 403.289422 - @@ -14270,8 +14270,8 @@ L 888.655669 403.289422 - @@ -14282,8 +14282,8 @@ L 908.232168 403.289422 - @@ -14294,8 +14294,8 @@ L 927.808667 403.289422 - @@ -14306,8 +14306,8 @@ L 947.385166 403.289422 - @@ -14318,8 +14318,8 @@ L 966.961665 403.289422 - @@ -14330,8 +14330,8 @@ L 986.538164 403.289422 - @@ -14359,8 +14359,8 @@ L 1006.114663 403.289422 - @@ -14381,8 +14381,8 @@ L 1015.902913 460.053058 - @@ -14403,8 +14403,8 @@ L 1015.902913 441.000475 - @@ -14425,312 +14425,312 @@ L 1015.902913 421.947893 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -14741,8 +14741,8 @@ L 1069.336955 403.289422 - @@ -14753,8 +14753,8 @@ L 1088.913454 403.289422 - @@ -14765,8 +14765,8 @@ L 1108.489953 403.289422 - @@ -14777,8 +14777,8 @@ L 1128.066452 403.289422 - @@ -14789,8 +14789,8 @@ L 1147.642951 403.289422 - @@ -14801,8 +14801,8 @@ L 1167.21945 403.289422 - @@ -14813,8 +14813,8 @@ L 1186.795949 403.289422 - @@ -14834,8 +14834,8 @@ L 1206.372448 403.289422 - @@ -14856,8 +14856,8 @@ L 1216.160697 459.109058 - @@ -14878,8 +14878,8 @@ L 1216.160697 439.747787 - @@ -14900,312 +14900,312 @@ L 1216.160697 420.386516 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -15216,8 +15216,8 @@ L 68.048032 503.910392 - @@ -15228,8 +15228,8 @@ L 87.624531 503.910392 - @@ -15240,8 +15240,8 @@ L 107.20103 503.910392 - @@ -15252,8 +15252,8 @@ L 126.777529 503.910392 - @@ -15264,8 +15264,8 @@ L 146.354028 503.910392 - @@ -15276,8 +15276,8 @@ L 165.930527 503.910392 - @@ -15288,8 +15288,8 @@ L 185.507026 503.910392 - @@ -15313,8 +15313,8 @@ L 205.083525 503.910392 - @@ -15335,8 +15335,8 @@ L 214.871775 577.611109 - @@ -15357,8 +15357,8 @@ L 214.871775 541.709741 - @@ -15379,312 +15379,312 @@ L 214.871775 505.808372 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -15695,8 +15695,8 @@ L 268.305817 503.910392 - @@ -15707,8 +15707,8 @@ L 287.882316 503.910392 - @@ -15719,8 +15719,8 @@ L 307.458815 503.910392 - @@ -15731,8 +15731,8 @@ L 327.035314 503.910392 - @@ -15743,8 +15743,8 @@ L 346.611813 503.910392 - @@ -15755,8 +15755,8 @@ L 366.188312 503.910392 - @@ -15767,8 +15767,8 @@ L 385.764811 503.910392 - @@ -15794,8 +15794,8 @@ L 405.34131 503.910392 - @@ -15816,8 +15816,8 @@ L 415.129559 577.914563 - @@ -15838,8 +15838,8 @@ L 415.129559 541.383889 - @@ -15860,312 +15860,312 @@ L 415.129559 504.853216 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -16176,8 +16176,8 @@ L 468.563601 503.910392 - @@ -16188,8 +16188,8 @@ L 488.1401 503.910392 - @@ -16200,8 +16200,8 @@ L 507.716599 503.910392 - @@ -16212,8 +16212,8 @@ L 527.293098 503.910392 - @@ -16224,8 +16224,8 @@ L 546.869597 503.910392 - @@ -16236,8 +16236,8 @@ L 566.446096 503.910392 - @@ -16248,8 +16248,8 @@ L 586.022595 503.910392 - @@ -16262,23 +16262,23 @@ L 605.599094 503.910392 - @@ -16298,8 +16298,8 @@ z - @@ -16320,8 +16320,8 @@ L 615.387344 545.262548 - @@ -16342,312 +16342,312 @@ L 615.387344 510.129014 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -16658,8 +16658,8 @@ L 668.821386 503.910392 - @@ -16670,8 +16670,8 @@ L 688.397885 503.910392 - @@ -16682,8 +16682,8 @@ L 707.974384 503.910392 - @@ -16694,8 +16694,8 @@ L 727.550883 503.910392 - @@ -16706,8 +16706,8 @@ L 747.127382 503.910392 - @@ -16718,8 +16718,8 @@ L 766.703881 503.910392 - @@ -16730,8 +16730,8 @@ L 786.28038 503.910392 - @@ -16759,8 +16759,8 @@ L 805.856879 503.910392 - @@ -16781,8 +16781,8 @@ L 815.645128 576.222331 - @@ -16803,8 +16803,8 @@ L 815.645128 541.570429 - @@ -16825,312 +16825,312 @@ L 815.645128 506.918527 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -17141,8 +17141,8 @@ L 869.07917 503.910392 - @@ -17153,8 +17153,8 @@ L 888.655669 503.910392 - @@ -17165,8 +17165,8 @@ L 908.232168 503.910392 - @@ -17177,8 +17177,8 @@ L 927.808667 503.910392 - @@ -17189,8 +17189,8 @@ L 947.385166 503.910392 - @@ -17201,8 +17201,8 @@ L 966.961665 503.910392 - @@ -17213,8 +17213,8 @@ L 986.538164 503.910392 - @@ -17246,8 +17246,8 @@ L 1006.114663 503.910392 - @@ -17268,8 +17268,8 @@ L 1015.902913 546.840348 - @@ -17290,312 +17290,312 @@ L 1015.902913 513.7117 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -17606,8 +17606,8 @@ L 1069.336955 503.910392 - @@ -17618,8 +17618,8 @@ L 1088.913454 503.910392 - @@ -17630,8 +17630,8 @@ L 1108.489953 503.910392 - @@ -17642,8 +17642,8 @@ L 1128.066452 503.910392 - @@ -17654,8 +17654,8 @@ L 1147.642951 503.910392 - @@ -17666,8 +17666,8 @@ L 1167.21945 503.910392 - @@ -17678,8 +17678,8 @@ L 1186.795949 503.910392 - @@ -17711,8 +17711,8 @@ L 1206.372448 503.910392 - @@ -17733,8 +17733,8 @@ L 1216.160697 571.28039 - @@ -17755,8 +17755,8 @@ L 1216.160697 542.093966 - @@ -17777,312 +17777,312 @@ L 1216.160697 512.907542 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -18093,8 +18093,8 @@ L 68.048032 602.693474 - @@ -18105,8 +18105,8 @@ L 87.624531 602.693474 - @@ -18117,8 +18117,8 @@ L 107.20103 602.693474 - @@ -18129,8 +18129,8 @@ L 126.777529 602.693474 - @@ -18141,8 +18141,8 @@ L 146.354028 602.693474 - @@ -18153,8 +18153,8 @@ L 165.930527 602.693474 - @@ -18165,8 +18165,8 @@ L 185.507026 602.693474 - @@ -18198,8 +18198,8 @@ L 205.083525 602.693474 - @@ -18220,8 +18220,8 @@ L 214.871775 661.475041 - @@ -18242,8 +18242,8 @@ L 214.871775 641.34259 - @@ -18264,312 +18264,312 @@ L 214.871775 621.210138 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -18580,8 +18580,8 @@ L 268.305817 602.693474 - @@ -18592,8 +18592,8 @@ L 287.882316 602.693474 - @@ -18604,8 +18604,8 @@ L 307.458815 602.693474 - @@ -18616,8 +18616,8 @@ L 327.035314 602.693474 - @@ -18628,8 +18628,8 @@ L 346.611813 602.693474 - @@ -18640,8 +18640,8 @@ L 366.188312 602.693474 - @@ -18652,8 +18652,8 @@ L 385.764811 602.693474 - @@ -18675,8 +18675,8 @@ L 405.34131 602.693474 - @@ -18697,8 +18697,8 @@ L 415.129559 643.649167 - @@ -18719,312 +18719,312 @@ L 415.129559 607.308214 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -19035,8 +19035,8 @@ L 468.563601 602.693474 - @@ -19047,8 +19047,8 @@ L 488.1401 602.693474 - @@ -19059,8 +19059,8 @@ L 507.716599 602.693474 - @@ -19071,8 +19071,8 @@ L 527.293098 602.693474 - @@ -19083,8 +19083,8 @@ L 546.869597 602.693474 - @@ -19095,8 +19095,8 @@ L 566.446096 602.693474 - @@ -19107,8 +19107,8 @@ L 586.022595 602.693474 - @@ -19140,8 +19140,8 @@ L 605.599094 602.693474 - @@ -19162,8 +19162,8 @@ L 615.387344 676.864714 - @@ -19184,8 +19184,8 @@ L 615.387344 644.090288 - @@ -19206,312 +19206,312 @@ L 615.387344 611.315861 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -19522,8 +19522,8 @@ L 668.821386 602.693474 - @@ -19534,8 +19534,8 @@ L 688.397885 602.693474 - @@ -19546,8 +19546,8 @@ L 707.974384 602.693474 - @@ -19558,8 +19558,8 @@ L 727.550883 602.693474 - @@ -19570,8 +19570,8 @@ L 747.127382 602.693474 - @@ -19582,8 +19582,8 @@ L 766.703881 602.693474 - @@ -19594,8 +19594,8 @@ L 786.28038 602.693474 - @@ -19616,8 +19616,8 @@ L 805.856879 602.693474 - @@ -19638,8 +19638,8 @@ L 815.645128 642.002901 - @@ -19660,312 +19660,312 @@ L 815.645128 605.474396 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -19976,8 +19976,8 @@ L 869.07917 602.693474 - @@ -19988,8 +19988,8 @@ L 888.655669 602.693474 - @@ -20000,8 +20000,8 @@ L 908.232168 602.693474 - @@ -20012,8 +20012,8 @@ L 927.808667 602.693474 - @@ -20024,8 +20024,8 @@ L 947.385166 602.693474 - @@ -20036,8 +20036,8 @@ L 966.961665 602.693474 - @@ -20048,8 +20048,8 @@ L 986.538164 602.693474 - @@ -20081,8 +20081,8 @@ L 1006.114663 602.693474 - @@ -20103,8 +20103,8 @@ L 1015.902913 644.227694 - @@ -20125,312 +20125,312 @@ L 1015.902913 609.436433 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -20441,8 +20441,8 @@ L 1069.336955 602.693474 - @@ -20453,8 +20453,8 @@ L 1088.913454 602.693474 - @@ -20465,8 +20465,8 @@ L 1108.489953 602.693474 - @@ -20477,8 +20477,8 @@ L 1128.066452 602.693474 - @@ -20489,8 +20489,8 @@ L 1147.642951 602.693474 - @@ -20501,8 +20501,8 @@ L 1167.21945 602.693474 - @@ -20513,8 +20513,8 @@ L 1186.795949 602.693474 - @@ -20537,8 +20537,8 @@ L 1206.372448 602.693474 - @@ -20559,8 +20559,8 @@ L 1216.160697 675.11496 - @@ -20581,312 +20581,312 @@ L 1216.160697 630.113333 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -20897,8 +20897,8 @@ L 68.048032 703.319568 - @@ -20909,8 +20909,8 @@ L 87.624531 703.319568 - @@ -20921,8 +20921,8 @@ L 107.20103 703.319568 - @@ -20933,8 +20933,8 @@ L 126.777529 703.319568 - @@ -20945,8 +20945,8 @@ L 146.354028 703.319568 - @@ -20957,8 +20957,8 @@ L 165.930527 703.319568 - @@ -20969,8 +20969,8 @@ L 185.507026 703.319568 - @@ -20983,30 +20983,30 @@ L 205.083525 703.319568 - @@ -21023,8 +21023,8 @@ z - @@ -21045,8 +21045,8 @@ L 214.871775 744.560369 - @@ -21067,312 +21067,312 @@ L 214.871775 710.963016 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -21383,8 +21383,8 @@ L 268.305817 703.319568 - @@ -21395,8 +21395,8 @@ L 287.882316 703.319568 - @@ -21407,8 +21407,8 @@ L 307.458815 703.319568 - @@ -21419,8 +21419,8 @@ L 327.035314 703.319568 - @@ -21431,8 +21431,8 @@ L 346.611813 703.319568 - @@ -21443,8 +21443,8 @@ L 366.188312 703.319568 - @@ -21455,8 +21455,8 @@ L 385.764811 703.319568 - @@ -21481,8 +21481,8 @@ L 405.34131 703.319568 - @@ -21503,8 +21503,8 @@ L 415.129559 775.837782 - @@ -21525,8 +21525,8 @@ L 415.129559 744.089211 - @@ -21547,312 +21547,312 @@ L 415.129559 712.340641 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -21863,8 +21863,8 @@ L 468.563601 703.319568 - @@ -21875,8 +21875,8 @@ L 488.1401 703.319568 - @@ -21887,8 +21887,8 @@ L 507.716599 703.319568 - @@ -21899,8 +21899,8 @@ L 527.293098 703.319568 - @@ -21911,8 +21911,8 @@ L 546.869597 703.319568 - @@ -21923,8 +21923,8 @@ L 566.446096 703.319568 - @@ -21935,8 +21935,8 @@ L 586.022595 703.319568 - @@ -21972,8 +21972,8 @@ L 605.599094 703.319568 - @@ -21994,8 +21994,8 @@ L 615.387344 762.420931 - @@ -22016,8 +22016,8 @@ L 615.387344 741.895085 - @@ -22038,312 +22038,312 @@ L 615.387344 721.369239 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -22354,8 +22354,8 @@ L 668.821386 703.319568 - @@ -22366,8 +22366,8 @@ L 688.397885 703.319568 - @@ -22378,8 +22378,8 @@ L 707.974384 703.319568 - @@ -22390,8 +22390,8 @@ L 727.550883 703.319568 - @@ -22402,8 +22402,8 @@ L 747.127382 703.319568 - @@ -22414,8 +22414,8 @@ L 766.703881 703.319568 - @@ -22426,8 +22426,8 @@ L 786.28038 703.319568 - @@ -22453,8 +22453,8 @@ L 805.856879 703.319568 - @@ -22475,8 +22475,8 @@ L 815.645128 773.259466 - @@ -22497,8 +22497,8 @@ L 815.645128 744.367451 - @@ -22519,312 +22519,312 @@ L 815.645128 715.475436 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -22835,8 +22835,8 @@ L 869.07917 703.319568 - @@ -22847,8 +22847,8 @@ L 888.655669 703.319568 - @@ -22859,8 +22859,8 @@ L 908.232168 703.319568 - @@ -22871,8 +22871,8 @@ L 927.808667 703.319568 - @@ -22883,8 +22883,8 @@ L 947.385166 703.319568 - @@ -22895,8 +22895,8 @@ L 966.961665 703.319568 - @@ -22907,8 +22907,8 @@ L 986.538164 703.319568 - @@ -22940,8 +22940,8 @@ L 1006.114663 703.319568 - @@ -22962,8 +22962,8 @@ L 1015.902913 746.939235 - @@ -22984,312 +22984,312 @@ L 1015.902913 704.257267 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -23300,8 +23300,8 @@ L 1069.336955 703.319568 - @@ -23312,8 +23312,8 @@ L 1088.913454 703.319568 - @@ -23324,8 +23324,8 @@ L 1108.489953 703.319568 - @@ -23336,8 +23336,8 @@ L 1128.066452 703.319568 - @@ -23348,8 +23348,8 @@ L 1147.642951 703.319568 - @@ -23360,8 +23360,8 @@ L 1167.21945 703.319568 - @@ -23372,8 +23372,8 @@ L 1186.795949 703.319568 - @@ -23407,8 +23407,8 @@ L 1206.372448 703.319568 - @@ -23429,8 +23429,8 @@ L 1216.160697 746.501124 - @@ -23451,312 +23451,312 @@ L 1216.160697 712.822114 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -23767,8 +23767,8 @@ L 68.048032 804.193813 - @@ -23779,8 +23779,8 @@ L 87.624531 804.193813 - @@ -23791,8 +23791,8 @@ L 107.20103 804.193813 - @@ -23803,8 +23803,8 @@ L 126.777529 804.193813 - @@ -23815,8 +23815,8 @@ L 146.354028 804.193813 - @@ -23827,8 +23827,8 @@ L 165.930527 804.193813 - @@ -23839,8 +23839,8 @@ L 185.507026 804.193813 - @@ -23865,8 +23865,8 @@ L 205.083525 804.193813 - @@ -23887,8 +23887,8 @@ L 214.871775 871.847388 - @@ -23909,312 +23909,312 @@ L 214.871775 836.313566 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -24225,8 +24225,8 @@ L 268.305817 804.193813 - @@ -24237,8 +24237,8 @@ L 287.882316 804.193813 - @@ -24249,8 +24249,8 @@ L 307.458815 804.193813 - @@ -24261,8 +24261,8 @@ L 327.035314 804.193813 - @@ -24273,8 +24273,8 @@ L 346.611813 804.193813 - @@ -24285,8 +24285,8 @@ L 366.188312 804.193813 - @@ -24297,8 +24297,8 @@ L 385.764811 804.193813 - @@ -24330,8 +24330,8 @@ L 405.34131 804.193813 - @@ -24352,8 +24352,8 @@ L 415.129559 861.33971 - @@ -24374,8 +24374,8 @@ L 415.129559 839.173974 - @@ -24396,312 +24396,312 @@ L 415.129559 817.008238 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -24712,8 +24712,8 @@ L 468.563601 804.193813 - @@ -24724,8 +24724,8 @@ L 488.1401 804.193813 - @@ -24736,8 +24736,8 @@ L 507.716599 804.193813 - @@ -24748,8 +24748,8 @@ L 527.293098 804.193813 - @@ -24760,8 +24760,8 @@ L 546.869597 804.193813 - @@ -24772,8 +24772,8 @@ L 566.446096 804.193813 - @@ -24784,8 +24784,8 @@ L 586.022595 804.193813 - @@ -24825,8 +24825,8 @@ L 605.599094 804.193813 - @@ -24847,8 +24847,8 @@ L 615.387344 864.252776 - @@ -24869,8 +24869,8 @@ L 615.387344 838.645973 - @@ -24891,312 +24891,312 @@ L 615.387344 813.03917 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -25207,8 +25207,8 @@ L 668.821386 804.193813 - @@ -25219,8 +25219,8 @@ L 688.397885 804.193813 - @@ -25231,8 +25231,8 @@ L 707.974384 804.193813 - @@ -25243,8 +25243,8 @@ L 727.550883 804.193813 - @@ -25255,8 +25255,8 @@ L 747.127382 804.193813 - @@ -25267,8 +25267,8 @@ L 766.703881 804.193813 - @@ -25279,8 +25279,8 @@ L 786.28038 804.193813 - @@ -25306,8 +25306,8 @@ L 805.856879 804.193813 - @@ -25328,8 +25328,8 @@ L 815.645128 862.613999 - @@ -25350,8 +25350,8 @@ L 815.645128 842.814399 - @@ -25372,312 +25372,312 @@ L 815.645128 823.014798 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -25688,8 +25688,8 @@ L 869.07917 804.193813 - @@ -25700,8 +25700,8 @@ L 888.655669 804.193813 - @@ -25712,8 +25712,8 @@ L 908.232168 804.193813 - @@ -25724,8 +25724,8 @@ L 927.808667 804.193813 - @@ -25736,8 +25736,8 @@ L 947.385166 804.193813 - @@ -25748,8 +25748,8 @@ L 966.961665 804.193813 - @@ -25760,8 +25760,8 @@ L 986.538164 804.193813 - @@ -25792,8 +25792,8 @@ L 1006.114663 804.193813 - @@ -25814,8 +25814,8 @@ L 1015.902913 842.257521 - @@ -25836,312 +25836,312 @@ L 1015.902913 804.883333 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -26152,8 +26152,8 @@ L 1069.336955 804.193813 - @@ -26164,8 +26164,8 @@ L 1088.913454 804.193813 - @@ -26176,8 +26176,8 @@ L 1108.489953 804.193813 - @@ -26188,8 +26188,8 @@ L 1128.066452 804.193813 - @@ -26200,8 +26200,8 @@ L 1147.642951 804.193813 - @@ -26212,8 +26212,8 @@ L 1167.21945 804.193813 - @@ -26224,8 +26224,8 @@ L 1186.795949 804.193813 - @@ -26252,8 +26252,8 @@ L 1206.372448 804.193813 - @@ -26274,8 +26274,8 @@ L 1216.160697 843.793546 - @@ -26296,312 +26296,312 @@ L 1216.160697 808.44002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -26612,8 +26612,8 @@ L 68.048032 905.441244 - @@ -26624,8 +26624,8 @@ L 87.624531 905.441244 - @@ -26636,8 +26636,8 @@ L 107.20103 905.441244 - @@ -26648,8 +26648,8 @@ L 126.777529 905.441244 - @@ -26660,8 +26660,8 @@ L 146.354028 905.441244 - @@ -26672,8 +26672,8 @@ L 165.930527 905.441244 - @@ -26684,8 +26684,8 @@ L 185.507026 905.441244 - @@ -26715,8 +26715,8 @@ L 205.083525 905.441244 - @@ -26737,8 +26737,8 @@ L 214.871775 947.044025 - @@ -26759,312 +26759,312 @@ L 214.871775 913.962917 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -27075,8 +27075,8 @@ L 268.305817 905.441244 - @@ -27087,8 +27087,8 @@ L 287.882316 905.441244 - @@ -27099,8 +27099,8 @@ L 307.458815 905.441244 - @@ -27111,8 +27111,8 @@ L 327.035314 905.441244 - @@ -27123,8 +27123,8 @@ L 346.611813 905.441244 - @@ -27135,8 +27135,8 @@ L 366.188312 905.441244 - @@ -27147,8 +27147,8 @@ L 385.764811 905.441244 - @@ -27161,14 +27161,14 @@ L 405.34131 905.441244 - @@ -27186,8 +27186,8 @@ z - @@ -27208,8 +27208,8 @@ L 415.129559 979.15993 - @@ -27230,8 +27230,8 @@ L 415.129559 942.458732 - @@ -27252,312 +27252,312 @@ L 415.129559 905.757535 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -27568,8 +27568,8 @@ L 468.563601 905.441244 - @@ -27580,8 +27580,8 @@ L 488.1401 905.441244 - @@ -27592,8 +27592,8 @@ L 507.716599 905.441244 - @@ -27604,8 +27604,8 @@ L 527.293098 905.441244 - @@ -27616,8 +27616,8 @@ L 546.869597 905.441244 - @@ -27628,8 +27628,8 @@ L 566.446096 905.441244 - @@ -27640,8 +27640,8 @@ L 586.022595 905.441244 - @@ -27667,8 +27667,8 @@ L 605.599094 905.441244 - @@ -27689,8 +27689,8 @@ L 615.387344 966.929056 - @@ -27711,8 +27711,8 @@ L 615.387344 944.271583 - @@ -27733,312 +27733,312 @@ L 615.387344 921.614109 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -28049,8 +28049,8 @@ L 668.821386 905.441244 - @@ -28061,8 +28061,8 @@ L 688.397885 905.441244 - @@ -28073,8 +28073,8 @@ L 707.974384 905.441244 - @@ -28085,8 +28085,8 @@ L 727.550883 905.441244 - @@ -28097,8 +28097,8 @@ L 747.127382 905.441244 - @@ -28109,8 +28109,8 @@ L 766.703881 905.441244 - @@ -28121,8 +28121,8 @@ L 786.28038 905.441244 - @@ -28154,8 +28154,8 @@ L 805.856879 905.441244 - @@ -28176,8 +28176,8 @@ L 815.645128 979.138946 - @@ -28198,312 +28198,312 @@ L 815.645128 941.708153 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -28514,8 +28514,8 @@ L 869.07917 905.441244 - @@ -28526,8 +28526,8 @@ L 888.655669 905.441244 - @@ -28538,8 +28538,8 @@ L 908.232168 905.441244 - @@ -28550,8 +28550,8 @@ L 927.808667 905.441244 - @@ -28562,8 +28562,8 @@ L 947.385166 905.441244 - @@ -28574,8 +28574,8 @@ L 966.961665 905.441244 - @@ -28586,8 +28586,8 @@ L 986.538164 905.441244 - @@ -28616,8 +28616,8 @@ L 1006.114663 905.441244 - @@ -28638,8 +28638,8 @@ L 1015.902913 977.186181 - @@ -28660,8 +28660,8 @@ L 1015.902913 944.805009 - @@ -28682,312 +28682,312 @@ L 1015.902913 912.423837 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -28998,8 +28998,8 @@ L 1069.336955 905.441244 - @@ -29010,8 +29010,8 @@ L 1088.913454 905.441244 - @@ -29022,8 +29022,8 @@ L 1108.489953 905.441244 - @@ -29034,8 +29034,8 @@ L 1128.066452 905.441244 - @@ -29046,8 +29046,8 @@ L 1147.642951 905.441244 - @@ -29058,8 +29058,8 @@ L 1167.21945 905.441244 - @@ -29070,8 +29070,8 @@ L 1186.795949 905.441244 - @@ -29099,8 +29099,8 @@ L 1206.372448 905.441244 - @@ -29121,8 +29121,8 @@ L 1216.160697 976.923785 - @@ -29143,8 +29143,8 @@ L 1216.160697 942.571476 - @@ -29165,312 +29165,312 @@ L 1216.160697 908.219168 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -29481,8 +29481,8 @@ L 68.048032 1003.205711 - @@ -29493,8 +29493,8 @@ L 87.624531 1003.205711 - @@ -29505,8 +29505,8 @@ L 107.20103 1003.205711 - @@ -29517,8 +29517,8 @@ L 126.777529 1003.205711 - @@ -29529,8 +29529,8 @@ L 146.354028 1003.205711 - @@ -29541,8 +29541,8 @@ L 165.930527 1003.205711 - @@ -29553,8 +29553,8 @@ L 185.507026 1003.205711 - @@ -29591,8 +29591,8 @@ L 205.083525 1003.205711 - @@ -29613,8 +29613,8 @@ L 214.871775 1057.966601 - @@ -29635,8 +29635,8 @@ L 214.871775 1037.72528 - @@ -29657,312 +29657,312 @@ L 214.871775 1017.483959 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -29973,8 +29973,8 @@ L 268.305817 1003.205711 - @@ -29985,8 +29985,8 @@ L 287.882316 1003.205711 - @@ -29997,8 +29997,8 @@ L 307.458815 1003.205711 - @@ -30009,8 +30009,8 @@ L 327.035314 1003.205711 - @@ -30021,8 +30021,8 @@ L 346.611813 1003.205711 - @@ -30033,8 +30033,8 @@ L 366.188312 1003.205711 - @@ -30045,8 +30045,8 @@ L 385.764811 1003.205711 - @@ -30075,8 +30075,8 @@ L 405.34131 1003.205711 - @@ -30097,8 +30097,8 @@ L 415.129559 1062.893756 - @@ -30119,8 +30119,8 @@ L 415.129559 1042.683129 - @@ -30141,312 +30141,312 @@ L 415.129559 1022.472503 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -30457,8 +30457,8 @@ L 468.563601 1003.205711 - @@ -30469,8 +30469,8 @@ L 488.1401 1003.205711 - @@ -30481,8 +30481,8 @@ L 507.716599 1003.205711 - @@ -30493,8 +30493,8 @@ L 527.293098 1003.205711 - @@ -30505,8 +30505,8 @@ L 546.869597 1003.205711 - @@ -30517,8 +30517,8 @@ L 566.446096 1003.205711 - @@ -30529,8 +30529,8 @@ L 586.022595 1003.205711 - @@ -30571,8 +30571,8 @@ L 605.599094 1003.205711 - @@ -30593,8 +30593,8 @@ L 615.387344 1074.297049 - @@ -30615,8 +30615,8 @@ L 615.387344 1042.412741 - @@ -30637,312 +30637,312 @@ L 615.387344 1010.528433 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -30953,8 +30953,8 @@ L 668.821386 1003.205711 - @@ -30965,8 +30965,8 @@ L 688.397885 1003.205711 - @@ -30977,8 +30977,8 @@ L 707.974384 1003.205711 - @@ -30989,8 +30989,8 @@ L 727.550883 1003.205711 - @@ -31001,8 +31001,8 @@ L 747.127382 1003.205711 - @@ -31013,8 +31013,8 @@ L 766.703881 1003.205711 - @@ -31025,8 +31025,8 @@ L 786.28038 1003.205711 - @@ -31057,8 +31057,8 @@ L 805.856879 1003.205711 - @@ -31079,8 +31079,8 @@ L 815.645128 1058.048639 - @@ -31101,8 +31101,8 @@ L 815.645128 1036.183599 - @@ -31123,312 +31123,312 @@ L 815.645128 1014.318559 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -31439,8 +31439,8 @@ L 869.07917 1003.205711 - @@ -31451,8 +31451,8 @@ L 888.655669 1003.205711 - @@ -31463,8 +31463,8 @@ L 908.232168 1003.205711 - @@ -31475,8 +31475,8 @@ L 927.808667 1003.205711 - @@ -31487,8 +31487,8 @@ L 947.385166 1003.205711 - @@ -31499,8 +31499,8 @@ L 966.961665 1003.205711 - @@ -31511,8 +31511,8 @@ L 986.538164 1003.205711 - @@ -31536,8 +31536,8 @@ L 1006.114663 1003.205711 - @@ -31558,8 +31558,8 @@ L 1015.902913 1075.415325 - @@ -31580,8 +31580,8 @@ L 1015.902913 1044.429662 - @@ -31602,312 +31602,312 @@ L 1015.902913 1013.444 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -31918,8 +31918,8 @@ L 1069.336955 1003.205711 - @@ -31930,8 +31930,8 @@ L 1088.913454 1003.205711 - @@ -31942,8 +31942,8 @@ L 1108.489953 1003.205711 - @@ -31954,8 +31954,8 @@ L 1128.066452 1003.205711 - @@ -31966,8 +31966,8 @@ L 1147.642951 1003.205711 - @@ -31978,8 +31978,8 @@ L 1167.21945 1003.205711 - @@ -31990,8 +31990,8 @@ L 1186.795949 1003.205711 - @@ -32029,8 +32029,8 @@ L 1206.372448 1003.205711 - @@ -32051,8 +32051,8 @@ L 1216.160697 1044.817291 - @@ -32073,312 +32073,312 @@ L 1216.160697 1011.089216 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -32389,8 +32389,8 @@ L 68.048032 1102.282316 - @@ -32401,8 +32401,8 @@ L 87.624531 1102.282316 - @@ -32413,8 +32413,8 @@ L 107.20103 1102.282316 - @@ -32425,8 +32425,8 @@ L 126.777529 1102.282316 - @@ -32437,8 +32437,8 @@ L 146.354028 1102.282316 - @@ -32449,8 +32449,8 @@ L 165.930527 1102.282316 - @@ -32461,8 +32461,8 @@ L 185.507026 1102.282316 - @@ -32499,8 +32499,8 @@ L 205.083525 1102.282316 - @@ -32521,8 +32521,8 @@ L 214.871775 1159.428538 - @@ -32543,8 +32543,8 @@ L 214.871775 1140.37385 - @@ -32565,312 +32565,312 @@ L 214.871775 1121.319162 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -32881,8 +32881,8 @@ L 268.305817 1102.282316 - @@ -32893,8 +32893,8 @@ L 287.882316 1102.282316 - @@ -32905,8 +32905,8 @@ L 307.458815 1102.282316 - @@ -32917,8 +32917,8 @@ L 327.035314 1102.282316 - @@ -32929,8 +32929,8 @@ L 346.611813 1102.282316 - @@ -32941,8 +32941,8 @@ L 366.188312 1102.282316 - @@ -32953,8 +32953,8 @@ L 385.764811 1102.282316 - @@ -32988,8 +32988,8 @@ L 405.34131 1102.282316 - @@ -33010,8 +33010,8 @@ L 415.129559 1160.988927 - @@ -33032,8 +33032,8 @@ L 415.129559 1139.201737 - @@ -33054,312 +33054,312 @@ L 415.129559 1117.414547 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -33370,8 +33370,8 @@ L 468.563601 1102.282316 - @@ -33382,8 +33382,8 @@ L 488.1401 1102.282316 - @@ -33394,8 +33394,8 @@ L 507.716599 1102.282316 - @@ -33406,8 +33406,8 @@ L 527.293098 1102.282316 - @@ -33418,8 +33418,8 @@ L 546.869597 1102.282316 - @@ -33430,8 +33430,8 @@ L 566.446096 1102.282316 - @@ -33442,8 +33442,8 @@ L 586.022595 1102.282316 - @@ -33481,8 +33481,8 @@ L 605.599094 1102.282316 - @@ -33503,8 +33503,8 @@ L 615.387344 1175.618886 - @@ -33525,8 +33525,8 @@ L 615.387344 1143.255394 - @@ -33547,312 +33547,312 @@ L 615.387344 1110.891902 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -33863,8 +33863,8 @@ L 668.821386 1102.282316 - @@ -33875,8 +33875,8 @@ L 688.397885 1102.282316 - @@ -33887,8 +33887,8 @@ L 707.974384 1102.282316 - @@ -33899,8 +33899,8 @@ L 727.550883 1102.282316 - @@ -33911,8 +33911,8 @@ L 747.127382 1102.282316 - @@ -33923,8 +33923,8 @@ L 766.703881 1102.282316 - @@ -33935,8 +33935,8 @@ L 786.28038 1102.282316 - @@ -33964,8 +33964,8 @@ L 805.856879 1102.282316 - @@ -33986,8 +33986,8 @@ L 815.645128 1140.87883 - @@ -34008,312 +34008,312 @@ L 815.645128 1104.769682 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -34324,8 +34324,8 @@ L 869.07917 1102.282316 - @@ -34336,8 +34336,8 @@ L 888.655669 1102.282316 - @@ -34348,8 +34348,8 @@ L 908.232168 1102.282316 - @@ -34360,8 +34360,8 @@ L 927.808667 1102.282316 - @@ -34372,8 +34372,8 @@ L 947.385166 1102.282316 - @@ -34384,8 +34384,8 @@ L 966.961665 1102.282316 - @@ -34396,8 +34396,8 @@ L 986.538164 1102.282316 - @@ -34420,8 +34420,8 @@ L 1006.114663 1102.282316 - @@ -34442,8 +34442,8 @@ L 1015.902913 1171.958418 - @@ -34464,8 +34464,8 @@ L 1015.902913 1142.083182 - @@ -34486,312 +34486,312 @@ L 1015.902913 1112.207947 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -34802,8 +34802,8 @@ L 1069.336955 1102.282316 - @@ -34814,8 +34814,8 @@ L 1088.913454 1102.282316 - @@ -34826,8 +34826,8 @@ L 1108.489953 1102.282316 - @@ -34838,8 +34838,8 @@ L 1128.066452 1102.282316 - @@ -34850,8 +34850,8 @@ L 1147.642951 1102.282316 - @@ -34862,8 +34862,8 @@ L 1167.21945 1102.282316 - @@ -34874,8 +34874,8 @@ L 1186.795949 1102.282316 - @@ -34904,8 +34904,8 @@ L 1206.372448 1102.282316 - @@ -34926,8 +34926,8 @@ L 1216.160697 1164.962414 - @@ -34948,8 +34948,8 @@ L 1216.160697 1141.737196 - @@ -34970,312 +34970,312 @@ L 1216.160697 1118.511977 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -35286,8 +35286,8 @@ L 68.048032 1203.417233 - @@ -35298,8 +35298,8 @@ L 87.624531 1203.417233 - @@ -35310,8 +35310,8 @@ L 107.20103 1203.417233 - @@ -35322,8 +35322,8 @@ L 126.777529 1203.417233 - @@ -35334,8 +35334,8 @@ L 146.354028 1203.417233 - @@ -35346,8 +35346,8 @@ L 165.930527 1203.417233 - @@ -35358,8 +35358,8 @@ L 185.507026 1203.417233 - @@ -35389,8 +35389,8 @@ L 205.083525 1203.417233 - @@ -35411,8 +35411,8 @@ L 214.871775 1245.062549 - @@ -35433,312 +35433,312 @@ L 214.871775 1203.846051 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -35749,8 +35749,8 @@ L 268.305817 1203.417233 - @@ -35761,8 +35761,8 @@ L 287.882316 1203.417233 - @@ -35773,8 +35773,8 @@ L 307.458815 1203.417233 - @@ -35785,8 +35785,8 @@ L 327.035314 1203.417233 - @@ -35797,8 +35797,8 @@ L 346.611813 1203.417233 - @@ -35809,8 +35809,8 @@ L 366.188312 1203.417233 - @@ -35821,8 +35821,8 @@ L 385.764811 1203.417233 - @@ -35864,8 +35864,8 @@ L 405.34131 1203.417233 - @@ -35886,8 +35886,8 @@ L 415.129559 1276.692966 - @@ -35908,8 +35908,8 @@ L 415.129559 1243.428675 - @@ -35930,312 +35930,312 @@ L 415.129559 1210.164384 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -36246,8 +36246,8 @@ L 468.563601 1203.417233 - @@ -36258,8 +36258,8 @@ L 488.1401 1203.417233 - @@ -36270,8 +36270,8 @@ L 507.716599 1203.417233 - @@ -36282,8 +36282,8 @@ L 527.293098 1203.417233 - @@ -36294,8 +36294,8 @@ L 546.869597 1203.417233 - @@ -36306,8 +36306,8 @@ L 566.446096 1203.417233 - @@ -36318,8 +36318,8 @@ L 586.022595 1203.417233 - @@ -36357,8 +36357,8 @@ L 605.599094 1203.417233 - @@ -36379,8 +36379,8 @@ L 615.387344 1277.621303 - @@ -36401,8 +36401,8 @@ L 615.387344 1242.716166 - @@ -36423,312 +36423,312 @@ L 615.387344 1207.811028 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -36739,8 +36739,8 @@ L 668.821386 1203.417233 - @@ -36751,8 +36751,8 @@ L 688.397885 1203.417233 - @@ -36763,8 +36763,8 @@ L 707.974384 1203.417233 - @@ -36775,8 +36775,8 @@ L 727.550883 1203.417233 - @@ -36787,8 +36787,8 @@ L 747.127382 1203.417233 - @@ -36799,8 +36799,8 @@ L 766.703881 1203.417233 - @@ -36811,8 +36811,8 @@ L 786.28038 1203.417233 - @@ -36848,8 +36848,8 @@ L 805.856879 1203.417233 - @@ -36870,8 +36870,8 @@ L 815.645128 1274.57208 - @@ -36892,8 +36892,8 @@ L 815.645128 1240.434838 - @@ -36914,312 +36914,312 @@ L 815.645128 1206.297595 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -37230,8 +37230,8 @@ L 869.07917 1203.417233 - @@ -37242,8 +37242,8 @@ L 888.655669 1203.417233 - @@ -37254,8 +37254,8 @@ L 908.232168 1203.417233 - @@ -37266,8 +37266,8 @@ L 927.808667 1203.417233 - @@ -37278,8 +37278,8 @@ L 947.385166 1203.417233 - @@ -37290,8 +37290,8 @@ L 966.961665 1203.417233 - @@ -37302,8 +37302,8 @@ L 986.538164 1203.417233 - @@ -37339,8 +37339,8 @@ L 1006.114663 1203.417233 - @@ -37361,8 +37361,8 @@ L 1015.902913 1274.350116 - @@ -37383,8 +37383,8 @@ L 1015.902913 1244.713437 - @@ -37405,312 +37405,312 @@ L 1015.902913 1215.076758 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -37721,8 +37721,8 @@ L 1069.336955 1203.417233 - @@ -37733,8 +37733,8 @@ L 1088.913454 1203.417233 - @@ -37745,8 +37745,8 @@ L 1108.489953 1203.417233 - @@ -37757,8 +37757,8 @@ L 1128.066452 1203.417233 - @@ -37769,8 +37769,8 @@ L 1147.642951 1203.417233 - @@ -37781,8 +37781,8 @@ L 1167.21945 1203.417233 - @@ -37793,8 +37793,8 @@ L 1186.795949 1203.417233 - @@ -37831,8 +37831,8 @@ L 1206.372448 1203.417233 - @@ -37853,8 +37853,8 @@ L 1216.160697 1269.263355 - @@ -37875,8 +37875,8 @@ L 1216.160697 1242.508442 - @@ -37897,312 +37897,312 @@ L 1216.160697 1215.75353 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -38213,8 +38213,8 @@ L 68.048032 1304.980918 - @@ -38225,8 +38225,8 @@ L 87.624531 1304.980918 - @@ -38237,8 +38237,8 @@ L 107.20103 1304.980918 - @@ -38249,8 +38249,8 @@ L 126.777529 1304.980918 - @@ -38261,8 +38261,8 @@ L 146.354028 1304.980918 - @@ -38273,8 +38273,8 @@ L 165.930527 1304.980918 - @@ -38285,8 +38285,8 @@ L 185.507026 1304.980918 - @@ -38319,8 +38319,8 @@ L 205.083525 1304.980918 - @@ -38341,8 +38341,8 @@ L 214.871775 1368.951521 - @@ -38363,8 +38363,8 @@ L 214.871775 1343.773716 - @@ -38385,312 +38385,312 @@ L 214.871775 1318.595911 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -38701,8 +38701,8 @@ L 268.305817 1304.980918 - @@ -38713,8 +38713,8 @@ L 287.882316 1304.980918 - @@ -38725,8 +38725,8 @@ L 307.458815 1304.980918 - @@ -38737,8 +38737,8 @@ L 327.035314 1304.980918 - @@ -38749,8 +38749,8 @@ L 346.611813 1304.980918 - @@ -38761,8 +38761,8 @@ L 366.188312 1304.980918 - @@ -38773,8 +38773,8 @@ L 385.764811 1304.980918 - @@ -38809,8 +38809,8 @@ L 405.34131 1304.980918 - @@ -38831,8 +38831,8 @@ L 415.129559 1374.078671 - @@ -38853,8 +38853,8 @@ L 415.129559 1346.585484 - @@ -38875,304 +38875,304 @@ L 415.129559 1319.092297 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -39187,73 +39187,73 @@ z - - - @@ -39278,25 +39278,25 @@ z - @@ -39324,51 +39324,51 @@ z - - @@ -39396,37 +39396,37 @@ z - - @@ -39466,75 +39466,75 @@ z - - - @@ -39583,33 +39583,33 @@ z - - - @@ -39648,71 +39648,71 @@ z - - - - @@ -39749,19 +39749,19 @@ z - @@ -39848,23 +39848,23 @@ z - - - - From 957cecb9f0ecd7c41b5d23d93f588d2664f95799 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 9 Apr 2026 23:13:46 +0100 Subject: [PATCH 15/21] Small fixes --- .github/CODEOWNERS | 1 + peps/pep-0830.rst | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8087be96d53..ec8a2cc6005 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -703,6 +703,7 @@ peps/pep-0826.rst @savannahostrowski peps/pep-0827.rst @1st1 peps/pep-0828.rst @ZeroIntensity peps/pep-0829.rst @warsaw +peps/pep-0830.rst @pablogsal @Fidget-Spinner @savannahostrowski # ... peps/pep-2026.rst @hugovk # ... diff --git a/peps/pep-0830.rst b/peps/pep-0830.rst index ff80891f88b..9c1af45de4b 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0830.rst @@ -3,12 +3,12 @@ Title: Frame Pointers Everywhere: Enabling System-Level Observability for Python Author: Pablo Galindo Salgado , Ken Jin , Savannah Ostrowski , -Discussions-To: +Discussions-To: Pending Status: Draft Type: Standards Track Created: 14-Mar-2026 Python-Version: 3.15 -Post-History: +Post-History: Pending Abstract @@ -920,6 +920,25 @@ Reference Implementation `_ +Rejected Ideas +============== + +This PEP rejects leaving frame pointers as a per-deployment opt-in because that +does not provide a reliable default observability story for Python users, Linux +distributions, or downstream tooling. It also rejects treating DWARF-based or +vendor-specific unwinding schemes as a sufficient general solution because they +do not provide the same low-overhead, universally available stack walking path +for kernel-assisted profiling and tracing. The alternatives discussed in +`Alternatives to Frame-Pointer Unwinding`_ remain useful in some contexts, but +they do not remove the need for frame pointers as the default baseline. + + +Change History +============== + +None at this time. + + Footnotes ========= From e7faa8c912cf2145d0b67f942f7a4f967bc6b603 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 10 Apr 2026 00:15:13 +0100 Subject: [PATCH 16/21] Address PR feedback --- .github/CODEOWNERS | 2 +- peps/{pep-0830.rst => pep-0831.rst} | 16 ++++++++-------- ...eline.svg => pep-0831_perf_over_baseline.svg} | 0 ...svg => pep-0831_perf_over_baseline_indiv.svg} | 0 4 files changed, 9 insertions(+), 9 deletions(-) rename peps/{pep-0830.rst => pep-0831.rst} (99%) rename peps/{pep-0830_perf_over_baseline.svg => pep-0831_perf_over_baseline.svg} (100%) rename peps/{pep-0830_perf_over_baseline_indiv.svg => pep-0831_perf_over_baseline_indiv.svg} (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ec8a2cc6005..e902f3153f3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -703,7 +703,7 @@ peps/pep-0826.rst @savannahostrowski peps/pep-0827.rst @1st1 peps/pep-0828.rst @ZeroIntensity peps/pep-0829.rst @warsaw -peps/pep-0830.rst @pablogsal @Fidget-Spinner @savannahostrowski +peps/pep-0831.rst @pablogsal @Fidget-Spinner @savannahostrowski # ... peps/pep-2026.rst @hugovk # ... diff --git a/peps/pep-0830.rst b/peps/pep-0831.rst similarity index 99% rename from peps/pep-0830.rst rename to peps/pep-0831.rst index 9c1af45de4b..0e5b8ad1ba4 100644 --- a/peps/pep-0830.rst +++ b/peps/pep-0831.rst @@ -1,4 +1,4 @@ -PEP: 830 +PEP: 831 Title: Frame Pointers Everywhere: Enabling System-Level Observability for Python Author: Pablo Galindo Salgado , Ken Jin , @@ -67,7 +67,7 @@ default experience for Python. The performance wins that profiling enables far outweigh the modest overhead of frame pointers. As Brendan Gregg notes: "I've seen frame pointers help find -performance wins ranging from 5% to 500%" [#gregg2024]_. A 1-2% overhead that +performance wins ranging from 5% to 500%" [#gregg2024]_. A 0.5-2% overhead that unlocks the ability to find 5-500% improvements is a favourable trade. What Are Frame Pointers? @@ -109,7 +109,7 @@ At optimisation levels ``-O1`` and above, GCC and Clang omit frame pointers by default [#gcc_fomit]_. This frees the ``%rbp`` register for general use, giving the optimiser one more register to work with. On x86-64 this is a gain of one register out of 16 (about 7%). The performance benefit is small -(typically 1-2%) but it was considered worthwhile when the convention was +(typically 0.5-2%) but it was considered worthwhile when the convention was established for 32-bit x86, where the gain was one register out of 6 (~20%). Without frame pointers, the linked list does not exist. Tools that need to @@ -611,7 +611,7 @@ system calls. A common misconception in the community is that frame pointers carry large overhead "because there was a single Python case that had a +10% slowdown." [#hn-fp]_ That single case is the eval loop benchmark; the geometric mean -across real workloads is 1-2%. +across real workloads is 0.5-2%. Detailed Performance Analysis of CPython with Frame Pointers ------------------------------------------------------------ @@ -764,7 +764,7 @@ This distinguishes frame pointers from other flags placed in ``CFLAGS_NODIST``: those flags (such as ``-Werror`` or internal warning suppressions) are correctness or policy controls that are meaningful per-compilation-unit. Frame pointers are an ecosystem-wide property that is only effective when all -participants cooperate. The 1-2% overhead measured on CPython is driven by its +participants cooperate. The 0.5-2% overhead measured on CPython is driven by its high density of small C helper function calls; typical C extension code does not exhibit the same call density and sees negligible overhead. @@ -861,7 +861,7 @@ are compiled separately and unaffected by Python's ``CFLAGS``. Extensions with hot scalar C loops (e.g., Cython-generated code) may see measurable but modest overhead. -For context, 1-2% geometric mean is comparable to overhead routinely accepted +For context, 0.5-2% geometric mean is comparable to overhead routinely accepted for build-time defaults such as ``-fstack-protector-strong`` (security) and the ASLR-compatible ``-fPIC`` flag for shared libraries. In return, the entire Python ecosystem gains the ability to produce complete flame graphs, accurate @@ -1074,11 +1074,11 @@ The first graph is the overall effect on pyperformance seen on each system. Apart from the Ubuntu AWS Graviton System, all system configurations have below 2% geometric mean and median slowdown: -.. image:: pep-0830_perf_over_baseline.svg +.. image:: pep-0831_perf_over_baseline.svg For individual benchmark results, see the following: -.. image:: pep-0830_perf_over_baseline_indiv.svg +.. image:: pep-0831_perf_over_baseline_indiv.svg Copyright diff --git a/peps/pep-0830_perf_over_baseline.svg b/peps/pep-0831_perf_over_baseline.svg similarity index 100% rename from peps/pep-0830_perf_over_baseline.svg rename to peps/pep-0831_perf_over_baseline.svg diff --git a/peps/pep-0830_perf_over_baseline_indiv.svg b/peps/pep-0831_perf_over_baseline_indiv.svg similarity index 100% rename from peps/pep-0830_perf_over_baseline_indiv.svg rename to peps/pep-0831_perf_over_baseline_indiv.svg From b231f21ee123ae833cd5fdd50cb756950b280183 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 11 Apr 2026 00:39:28 +0800 Subject: [PATCH 17/21] Update new results, add alt text --- peps/pep-0831.rst | 26 +- peps/pep-0831_perf_over_baseline.svg | 2687 +- peps/pep-0831_perf_over_baseline_indiv.svg | 43644 +++++++++---------- 3 files changed, 23162 insertions(+), 23195 deletions(-) diff --git a/peps/pep-0831.rst b/peps/pep-0831.rst index 0e5b8ad1ba4..e69b444fc7f 100644 --- a/peps/pep-0831.rst +++ b/peps/pep-0831.rst @@ -837,16 +837,16 @@ pyperformance JSON files can be found in [#benchmarks]_. Benchmark visualization can be found in the Appendix: ===================================== ======================= -Machine Geometric mean overhead +Machine Geometric mean effect ===================================== ======================= -Apple M2 Mac Mini (arm64) 1.006x slower -macOS M3 Pro (arm64) 1.001x slower -Raspberry Pi (aarch64). 1.002x slower -Ampere Altra Max (aarch64) 1.020x slower -AWS Graviton c7g.16xlarge (aarch64) 1.027x slower -Intel i7 12700H (x86-64) 1.019x slower -AMD EPYC 9654 (x86-64) 1.008x slower -Intel Xeon Platinum 8480 (x86-64) 1.006x slower +Apple M2 Mac Mini (arm64) 0.1% faster +macOS M3 Pro (arm64) 0.1% slower +Raspberry Pi (aarch64). 0.2% slower +Ampere Altra Max (aarch64) 0.9% faster +AWS Graviton c7g.16xlarge (aarch64) 0.8% slower +Intel i7 12700H (x86-64) 1.9% slower +AMD EPYC 9654 (x86-64) 1.7% slower +Intel Xeon Platinum 8480 (x86-64) 1.5% slower ===================================== ======================= This overhead applies to both the interpreter and to C extensions that inherit @@ -1071,15 +1071,17 @@ individual benchmark's median, while orange lines are the median of our data poi Hollow circles reperesent outliers. The first graph is the overall effect on pyperformance seen on each system. -Apart from the Ubuntu AWS Graviton System, all system configurations have below 2% -geometric mean and median slowdown: +All system configurations have below 2% geometric mean and median slowdown: .. image:: pep-0831_perf_over_baseline.svg + :alt: Overall results for the entire pyperformance benchmark suite on + various system configurations. For individual benchmark results, see the following: .. image:: pep-0831_perf_over_baseline_indiv.svg - + :alt: Individual benchmarks results from the pyperformance benchmark + suite on various system configurations. Copyright ========= diff --git a/peps/pep-0831_perf_over_baseline.svg b/peps/pep-0831_perf_over_baseline.svg index 7e098a25398..c09c9dbdde4 100644 --- a/peps/pep-0831_perf_over_baseline.svg +++ b/peps/pep-0831_perf_over_baseline.svg @@ -6,7 +6,7 @@ - 2026-04-09T23:41:26.447009 + 2026-04-11T00:31:04.859382 image/svg+xml @@ -21,218 +21,218 @@ - - - + - - + - - - - - - - @@ -249,108 +249,108 @@ z - + - + - - - - @@ -370,172 +370,172 @@ z - + - + - - - - - - - @@ -555,141 +555,141 @@ z - + - + - - - - - - - @@ -721,163 +721,163 @@ z - + - + - - - - - - - - @@ -918,67 +918,67 @@ z - + - + - - - - @@ -1009,114 +1009,114 @@ z - + - + - - - - - @@ -1145,71 +1145,71 @@ z - + - + - - @@ -1251,73 +1251,73 @@ z - - - @@ -1348,62 +1348,62 @@ z - + - - + - - + + - - + - + - + - + @@ -1414,139 +1414,95 @@ L 457.79976 151.292846 - + - + - - - + + + - - + + - + - + - - + + - + - + - + - - + + - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + @@ -1574,485 +1530,494 @@ L 457.79976 6.799202 - + + + + + + + + + + + + + - + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - + + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - + + + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - - - - + + + + + + + + + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - + + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - + + + + + + + + + + + + - - + - - - +" clip-path="url(#p2f101e0340)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - - - - - - - + - + + + + + + + + - + + + + + + + - + + + + - + + + + - - + + + - - - - - - + + + - - - + + + - - - + + + - - - + + + - - - - + - - - - + - - - - + - - - - + - + - + - + - + - - - - - - - - - - - - - + - - - - - - - + - + - @@ -2066,16 +2031,16 @@ z - - + - + @@ -2088,8 +2053,8 @@ z - - + + diff --git a/peps/pep-0831_perf_over_baseline_indiv.svg b/peps/pep-0831_perf_over_baseline_indiv.svg index a0f67ba162a..2004d83fb23 100644 --- a/peps/pep-0831_perf_over_baseline_indiv.svg +++ b/peps/pep-0831_perf_over_baseline_indiv.svg @@ -6,7 +6,7 @@ - 2026-04-09T21:55:00.790820 + 2026-04-11T00:31:01.619141 image/svg+xml @@ -21,224 +21,224 @@ - - - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - @@ -252,79 +252,79 @@ z - + - - + - + - - - - @@ -338,18 +338,18 @@ z - + - + - + @@ -360,610 +360,610 @@ L 214.871775 7.213396 - +" clip-path="url(#p68f595618b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p68f595618b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - @@ -989,56 +989,56 @@ z - + - + - + - @@ -1052,18 +1052,18 @@ z - + - + - + @@ -1074,18 +1074,18 @@ L 415.129559 43.41197 - + - + - + @@ -1096,538 +1096,538 @@ L 415.129559 9.652006 - +" clip-path="url(#pd936f69c24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd936f69c24)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - @@ -1660,18 +1660,18 @@ z - + - + - + @@ -1682,18 +1682,18 @@ L 615.387344 74.310064 - + - + - + @@ -1704,18 +1704,18 @@ L 615.387344 43.356462 - + - + - + @@ -1726,407 +1726,407 @@ L 615.387344 12.402859 - +" clip-path="url(#p3e807ebea0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3e807ebea0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2159,47 +2159,47 @@ L 805.856879 3.00024 - + - + - + - @@ -2213,18 +2213,18 @@ z - + - + - + @@ -2235,18 +2235,18 @@ L 815.645128 41.683085 - + - + - + @@ -2257,407 +2257,407 @@ L 815.645128 21.472558 - +" clip-path="url(#pd8919acf90)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd8919acf90)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2677,52 +2677,52 @@ L 1006.114663 3.00024 - + - + - + - - @@ -2736,18 +2736,18 @@ z - + - + - + @@ -2758,18 +2758,18 @@ L 1015.902913 44.826325 - + - + - + @@ -2780,407 +2780,407 @@ L 1015.902913 21.030463 - +" clip-path="url(#p82d5306110)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p82d5306110)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3203,18 +3203,18 @@ L 1206.372448 3.00024 - + - + - + @@ -3225,18 +3225,18 @@ L 1216.160697 72.696506 - + - + - + @@ -3247,18 +3247,18 @@ L 1216.160697 42.172905 - + - + - + @@ -3269,419 +3269,419 @@ L 1216.160697 11.649304 - +" clip-path="url(#pd398ef15bd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pd398ef15bd)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - @@ -3713,40 +3713,40 @@ z - + - + - - + + - - + + - + - + - + @@ -3757,429 +3757,429 @@ L 214.871775 144.850938 - + - + - - + + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p2b35d4be4f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4211,18 +4211,18 @@ L 405.34131 104.162832 - + - + - + @@ -4233,18 +4233,18 @@ L 415.129559 175.285671 - + - + - + @@ -4255,18 +4255,18 @@ L 415.129559 146.52958 - + - + - + @@ -4277,407 +4277,407 @@ L 415.129559 117.773489 - +" clip-path="url(#p207133dd3b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p207133dd3b)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4699,18 +4699,18 @@ L 605.599094 104.162832 - + - + - + @@ -4721,18 +4721,18 @@ L 615.387344 176.240524 - + - + - + @@ -4743,18 +4743,18 @@ L 615.387344 145.381651 - + - + - + @@ -4765,407 +4765,407 @@ L 615.387344 114.522777 - +" clip-path="url(#pb0ff18b154)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb0ff18b154)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -5190,18 +5190,18 @@ L 805.856879 104.162832 - + - + - + @@ -5212,18 +5212,18 @@ L 815.645128 147.350268 - + - + - + @@ -5234,462 +5234,462 @@ L 815.645128 104.563972 - +" clip-path="url(#p7dade621b0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p7dade621b0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - @@ -5717,18 +5717,18 @@ z - + - + - + @@ -5739,18 +5739,18 @@ L 1015.902913 144.86653 - + - + - + @@ -5761,407 +5761,407 @@ L 1015.902913 109.143705 - +" clip-path="url(#pbb6426bb61)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pbb6426bb61)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -6181,18 +6181,18 @@ L 1206.372448 104.162832 - + - + - + @@ -6203,18 +6203,18 @@ L 1216.160697 170.408368 - + - + - + @@ -6225,18 +6225,18 @@ L 1216.160697 137.596004 - + - + - + @@ -6247,432 +6247,432 @@ L 1216.160697 104.78364 - +" clip-path="url(#p42d73db31e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p42d73db31e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - @@ -6691,18 +6691,18 @@ z - + - + - + @@ -6713,18 +6713,18 @@ L 214.871775 243.740616 - + - + - + @@ -6735,407 +6735,407 @@ L 214.871775 207.972769 - +" clip-path="url(#p0796fe6db8)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0796fe6db8)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -7147,18 +7147,18 @@ L 405.34131 204.967916 - + - + - + @@ -7169,18 +7169,18 @@ L 415.129559 260.481363 - + - + - + @@ -7191,18 +7191,18 @@ L 415.129559 241.287733 - + - + - + @@ -7213,407 +7213,407 @@ L 415.129559 222.094102 - +" clip-path="url(#pf6ac23f088)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pf6ac23f088)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -7634,18 +7634,18 @@ L 605.599094 204.967916 - + - + - + @@ -7656,18 +7656,18 @@ L 615.387344 268.009917 - + - + - + @@ -7678,18 +7678,18 @@ L 615.387344 245.376846 - + - + - + @@ -7700,407 +7700,407 @@ L 615.387344 222.743776 - +" clip-path="url(#p564102b21c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p564102b21c)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -8117,18 +8117,18 @@ L 805.856879 204.967916 - + - + - + @@ -8139,18 +8139,18 @@ L 815.645128 269.985671 - + - + - + @@ -8161,18 +8161,18 @@ L 815.645128 244.294062 - + - + - + @@ -8183,407 +8183,407 @@ L 815.645128 218.602454 - +" clip-path="url(#p3d0e38139f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p3d0e38139f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -8606,18 +8606,18 @@ L 1006.114663 204.967916 - + - + - + @@ -8628,18 +8628,18 @@ L 1015.902913 277.113679 - + - + - + @@ -8650,18 +8650,18 @@ L 1015.902913 241.990957 - + - + - + @@ -8672,407 +8672,407 @@ L 1015.902913 206.868235 - +" clip-path="url(#pb8b83565c9)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pb8b83565c9)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -9091,18 +9091,18 @@ L 1206.372448 204.967916 - + - + - + @@ -9113,18 +9113,18 @@ L 1216.160697 278.298952 - + - + - + @@ -9135,18 +9135,18 @@ L 1216.160697 242.012778 - + - + - + @@ -9157,407 +9157,407 @@ L 1216.160697 205.726604 - +" clip-path="url(#p0906b80858)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p0906b80858)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -9572,18 +9572,18 @@ L 205.083525 305.524955 - + - + - + @@ -9594,18 +9594,18 @@ L 214.871775 378.998614 - + - + - + @@ -9616,407 +9616,407 @@ L 214.871775 342.131 - +" clip-path="url(#pce8a2918d4)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pce8a2918d4)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -10036,18 +10036,18 @@ L 405.34131 305.524955 - + - + - + @@ -10058,18 +10058,18 @@ L 415.129559 362.000832 - + - + - + @@ -10080,18 +10080,18 @@ L 415.129559 343.118089 - + - + - + @@ -10102,407 +10102,407 @@ L 415.129559 324.235347 - +" clip-path="url(#peb70cfa0e6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#peb70cfa0e6)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -10524,18 +10524,18 @@ L 605.599094 305.524955 - + - + - + @@ -10546,18 +10546,18 @@ L 615.387344 378.727289 - + - + - + @@ -10568,407 +10568,407 @@ L 615.387344 341.477643 - +" clip-path="url(#p55e6824f54)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p55e6824f54)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -10984,18 +10984,18 @@ L 805.856879 305.524955 - + - + - + @@ -11006,18 +11006,18 @@ L 815.645128 343.333845 - + - + - + @@ -11028,407 +11028,407 @@ L 815.645128 306.531717 - +" clip-path="url(#p9049650b49)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9049650b49)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -11443,18 +11443,18 @@ L 1006.114663 305.524955 - + - + - + @@ -11465,18 +11465,18 @@ L 1015.902913 372.235105 - + - + - + @@ -11487,18 +11487,18 @@ L 1015.902913 344.054112 - + - + - + @@ -11509,407 +11509,407 @@ L 1015.902913 315.873118 - +" clip-path="url(#p02abd0de56)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p02abd0de56)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -11927,21 +11927,21 @@ L 1206.372448 305.524955 - + - + - - - + + + - + @@ -11949,43 +11949,21 @@ L 1216.160697 361.859431 - + - + - - - - - - - - - - - - - - - - - - - - - - + + - + @@ -11993,427 +11971,427 @@ L 1216.160697 321.644599 - +" clip-path="url(#pafd283a45b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + - @@ -12429,20 +12407,20 @@ z - - - + + + - + - + - + - + @@ -12451,20 +12429,20 @@ L 214.871775 462.035844 - - - + + + - + - + - + - + @@ -12473,20 +12451,20 @@ L 214.871775 442.305118 - - - + + + - + - + - + - + @@ -12497,407 +12475,407 @@ L 214.871775 422.574393 - +" clip-path="url(#p90dbfaf8f1)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -12907,20 +12885,20 @@ L 405.34131 403.289422 - - - + + + - + - + - + - + @@ -12929,20 +12907,20 @@ L 415.129559 468.509948 - - - + + + - + - + - + - + @@ -12951,20 +12929,20 @@ L 415.129559 438.44403 - - - + + + - + - + - + - + @@ -12975,407 +12953,407 @@ L 415.129559 408.378111 - +" clip-path="url(#p9fa24d9ed5)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -13390,20 +13368,20 @@ L 605.599094 403.289422 - - - + + + - + - + - + - + @@ -13412,20 +13390,20 @@ L 615.387344 473.769116 - - - + + + - + - + - + - + @@ -13434,20 +13412,20 @@ L 615.387344 441.410623 - - - + + + - + - + - + - + @@ -13458,407 +13436,407 @@ L 615.387344 409.052129 - +" clip-path="url(#p4203bf405e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -13874,20 +13852,20 @@ L 805.856879 403.289422 - - - + + + - + - + - + - + @@ -13896,20 +13874,20 @@ L 815.645128 466.395515 - - - + + + - + - + - + - + @@ -13918,20 +13896,20 @@ L 815.645128 444.547003 - - - + + + - + - + - + - + @@ -13942,407 +13920,407 @@ L 815.645128 422.698491 - +" clip-path="url(#pa0de86e785)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -14357,20 +14335,20 @@ L 1006.114663 403.289422 - - - + + + - + - + - + - + @@ -14379,20 +14357,20 @@ L 1015.902913 460.053058 - - - + + + - + - + - + - + @@ -14401,20 +14379,20 @@ L 1015.902913 441.000475 - - - + + + - + - + - + - + @@ -14425,427 +14403,427 @@ L 1015.902913 421.947893 - +" clip-path="url(#p265d91c476)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + - - - + + + - + - + - + - + @@ -14854,20 +14832,20 @@ L 1216.160697 459.109058 - - - + + + - + - + - + - + @@ -14876,20 +14854,20 @@ L 1216.160697 439.747787 - - - + + + - + - + - + - + @@ -14900,407 +14878,407 @@ L 1216.160697 420.386516 - +" clip-path="url(#p9be4310a52)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -15311,20 +15289,20 @@ L 205.083525 503.910392 - - - + + + - + - + - + - + @@ -15333,20 +15311,20 @@ L 214.871775 577.611109 - - - + + + - + - + - + - + @@ -15355,20 +15333,20 @@ L 214.871775 541.709741 - - - + + + - + - + - + - + @@ -15379,407 +15357,407 @@ L 214.871775 505.808372 - +" clip-path="url(#p6a2371719c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -15792,20 +15770,20 @@ L 405.34131 503.910392 - - - + + + - + - + - + - + @@ -15814,20 +15792,20 @@ L 415.129559 577.914563 - - - + + + - + - + - + - + @@ -15836,20 +15814,20 @@ L 415.129559 541.383889 - - - + + + - + - + - + - + @@ -15860,425 +15838,425 @@ L 415.129559 504.853216 - +" clip-path="url(#pbc3d8547fe)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + - @@ -16296,20 +16274,20 @@ z - - - + + + - + - + - + - + @@ -16318,20 +16296,20 @@ L 615.387344 545.262548 - - - + + + - + - + - + - + @@ -16342,407 +16320,407 @@ L 615.387344 510.129014 - +" clip-path="url(#p6d5b5ca447)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -16757,20 +16735,20 @@ L 805.856879 503.910392 - - - + + + - + - + - + - + @@ -16779,20 +16757,20 @@ L 815.645128 576.222331 - - - + + + - + - + - + - + @@ -16801,20 +16779,20 @@ L 815.645128 541.570429 - - - + + + - + - + - + - + @@ -16825,407 +16803,407 @@ L 815.645128 506.918527 - +" clip-path="url(#p247b0a508f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -17244,20 +17222,20 @@ L 1006.114663 503.910392 - - - + + + - + - + - + - + @@ -17266,20 +17244,20 @@ L 1015.902913 546.840348 - - - + + + - + - + - + - + @@ -17290,407 +17268,407 @@ L 1015.902913 513.7117 - +" clip-path="url(#p9744b4e18c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -17709,20 +17687,20 @@ L 1206.372448 503.910392 - - - + + + - + - + - + - + @@ -17731,20 +17709,20 @@ L 1216.160697 571.28039 - - - + + + - + - + - + - + @@ -17753,20 +17731,20 @@ L 1216.160697 542.093966 - - - + + + - + - + - + - + @@ -17777,407 +17755,407 @@ L 1216.160697 512.907542 - +" clip-path="url(#p0c2102ca93)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -18196,20 +18174,20 @@ L 205.083525 602.693474 - - - + + + - + - + - + - + @@ -18218,20 +18196,20 @@ L 214.871775 661.475041 - - - + + + - + - + - + - + @@ -18240,20 +18218,20 @@ L 214.871775 641.34259 - - - + + + - + - + - + - + @@ -18264,407 +18242,407 @@ L 214.871775 621.210138 - +" clip-path="url(#pe3e3e7a8dd)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + @@ -18673,20 +18651,20 @@ L 405.34131 602.693474 - - - + + + - + - + - + - + @@ -18695,20 +18673,20 @@ L 415.129559 643.649167 - - - + + + - + - + - + - + @@ -18719,407 +18697,407 @@ L 415.129559 607.308214 - +" clip-path="url(#p3cb6d3c073)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -19138,20 +19116,20 @@ L 605.599094 602.693474 - - - + + + - + - + - + - + @@ -19160,20 +19138,20 @@ L 615.387344 676.864714 - - - + + + - + - + - + - + @@ -19182,20 +19160,20 @@ L 615.387344 644.090288 - - - + + + - + - + - + - + @@ -19206,407 +19184,407 @@ L 615.387344 611.315861 - +" clip-path="url(#pab558e0bef)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -19614,20 +19592,20 @@ L 805.856879 602.693474 - - - + + + - + - + - + - + @@ -19636,20 +19614,20 @@ L 815.645128 642.002901 - - - + + + - + - + - + - + @@ -19660,407 +19638,407 @@ L 815.645128 605.474396 - +" clip-path="url(#p7f0866093f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + @@ -20079,20 +20057,20 @@ L 1006.114663 602.693474 - - - + + + - + - + - + - + @@ -20101,20 +20079,20 @@ L 1015.902913 644.227694 - - - + + + - + - + - + - + @@ -20125,407 +20103,407 @@ L 1015.902913 609.436433 - +" clip-path="url(#p5847100cb7)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + @@ -20535,20 +20513,20 @@ L 1206.372448 602.693474 - - - + + + - + - + - + - + @@ -20557,20 +20535,20 @@ L 1216.160697 675.11496 - - - + + + - + - + - + - + @@ -20581,432 +20559,432 @@ L 1216.160697 630.113333 - +" clip-path="url(#pf0a13aa220)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - @@ -21021,20 +20999,20 @@ z - - - + + + - + - + - + - + @@ -21043,20 +21021,20 @@ L 214.871775 744.560369 - - - + + + - + - + - + - + @@ -21067,407 +21045,407 @@ L 214.871775 710.963016 - +" clip-path="url(#pdf61aa2d24)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + @@ -21479,20 +21457,20 @@ L 405.34131 703.319568 - - - + + + - + - + - + - + @@ -21501,20 +21479,20 @@ L 415.129559 775.837782 - - - + + + - + - + - + - + @@ -21523,20 +21501,20 @@ L 415.129559 744.089211 - - - + + + - + - + - + - + @@ -21547,407 +21525,407 @@ L 415.129559 712.340641 - +" clip-path="url(#p61e04d0cc6)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -21970,20 +21948,20 @@ L 605.599094 703.319568 - - - + + + - + - + - + - + @@ -21992,20 +21970,20 @@ L 615.387344 762.420931 - - - + + + - + - + - + - + @@ -22014,20 +21992,20 @@ L 615.387344 741.895085 - - - + + + - + - + - + - + @@ -22038,407 +22016,407 @@ L 615.387344 721.369239 - +" clip-path="url(#pbe73163f81)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + @@ -22451,20 +22429,20 @@ L 805.856879 703.319568 - - - + + + - + - + - + - + @@ -22473,20 +22451,20 @@ L 815.645128 773.259466 - - - + + + - + - + - + - + @@ -22495,20 +22473,20 @@ L 815.645128 744.367451 - - - + + + - + - + - + - + @@ -22519,407 +22497,407 @@ L 815.645128 715.475436 - +" clip-path="url(#p6199a3ebf0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -22938,20 +22916,20 @@ L 1006.114663 703.319568 - - - + + + - + - + - + - + @@ -22960,20 +22938,20 @@ L 1015.902913 746.939235 - - - + + + - + - + - + - + @@ -22984,407 +22962,407 @@ L 1015.902913 704.257267 - +" clip-path="url(#p2c2dc37cce)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - - - - - - - + - +" clip-path="url(#p2c2dc37cce)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -23405,20 +23383,20 @@ L 1206.372448 703.319568 - - - + + + - + - + - + - + @@ -23427,20 +23405,20 @@ L 1216.160697 746.501124 - - - + + + - + - + - + - + @@ -23451,407 +23429,407 @@ L 1216.160697 712.822114 - +" clip-path="url(#pbfe3716bd7)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -23863,20 +23841,20 @@ L 205.083525 804.193813 - - - + + + - + - + - + - + @@ -23885,20 +23863,20 @@ L 214.871775 871.847388 - - - + + + - + - + - + - + @@ -23909,407 +23887,407 @@ L 214.871775 836.313566 - +" clip-path="url(#peaf06a2a46)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -24328,20 +24306,20 @@ L 405.34131 804.193813 - - - + + + - + - + - + - + @@ -24350,20 +24328,20 @@ L 415.129559 861.33971 - - - + + + - + - + - + - + @@ -24372,20 +24350,20 @@ L 415.129559 839.173974 - - - + + + - + - + - + - + @@ -24396,407 +24374,407 @@ L 415.129559 817.008238 - +" clip-path="url(#pd0ec10a454)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -24823,20 +24801,20 @@ L 605.599094 804.193813 - - - + + + - + - + - + - + @@ -24845,20 +24823,20 @@ L 615.387344 864.252776 - - - + + + - + - + - + - + @@ -24867,20 +24845,20 @@ L 615.387344 838.645973 - - - + + + - + - + - + - + @@ -24891,407 +24869,407 @@ L 615.387344 813.03917 - +" clip-path="url(#pbae89ca398)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -25304,20 +25282,20 @@ L 805.856879 804.193813 - - - + + + - + - + - + - + @@ -25326,20 +25304,20 @@ L 815.645128 862.613999 - - - + + + - + - + - + - + @@ -25348,20 +25326,20 @@ L 815.645128 842.814399 - - - + + + - + - + - + - + @@ -25372,407 +25350,407 @@ L 815.645128 823.014798 - +" clip-path="url(#p92f4d3597b)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -25790,20 +25768,20 @@ L 1006.114663 804.193813 - - - + + + - + - + - + - + @@ -25812,20 +25790,20 @@ L 1015.902913 842.257521 - - - + + + - + - + - + - + @@ -25836,407 +25814,407 @@ L 1015.902913 804.883333 - +" clip-path="url(#p0c5ceb3827)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -26250,20 +26228,20 @@ L 1206.372448 804.193813 - - - + + + - + - + - + - + @@ -26272,20 +26250,20 @@ L 1216.160697 843.793546 - - - + + + - + - + - + - + @@ -26296,407 +26274,407 @@ L 1216.160697 808.44002 - +" clip-path="url(#p2b57494a5e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -26713,20 +26691,20 @@ L 205.083525 905.441244 - - - + + + - + - + - + - + @@ -26735,20 +26713,20 @@ L 214.871775 947.044025 - - - + + + - + - + - + - + @@ -26759,416 +26737,416 @@ L 214.871775 913.962917 - +" clip-path="url(#pfcef292a8a)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + - @@ -27184,20 +27162,20 @@ z - - - + + + - + - + - + - + @@ -27206,20 +27184,20 @@ L 415.129559 979.15993 - - - + + + - + - + - + - + @@ -27228,20 +27206,20 @@ L 415.129559 942.458732 - - - + + + - + - + - + - + @@ -27252,407 +27230,407 @@ L 415.129559 905.757535 - +" clip-path="url(#pb4bb2db30a)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -27665,20 +27643,20 @@ L 605.599094 905.441244 - - - + + + - + - + - + - + @@ -27687,20 +27665,20 @@ L 615.387344 966.929056 - - - + + + - + - + - + - + @@ -27709,20 +27687,20 @@ L 615.387344 944.271583 - - - + + + - + - + - + - + @@ -27733,407 +27711,407 @@ L 615.387344 921.614109 - +" clip-path="url(#p23c33d3660)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -28152,20 +28130,20 @@ L 805.856879 905.441244 - - - + + + - + - + - + - + @@ -28174,20 +28152,20 @@ L 815.645128 979.138946 - - - + + + - + - + - + - + @@ -28198,407 +28176,407 @@ L 815.645128 941.708153 - +" clip-path="url(#pd2dc55f736)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -28614,20 +28592,20 @@ L 1006.114663 905.441244 - - - + + + - + - + - + - + @@ -28636,20 +28614,20 @@ L 1015.902913 977.186181 - - - + + + - + - + - + - + @@ -28658,20 +28636,20 @@ L 1015.902913 944.805009 - - - + + + - + - + - + - + @@ -28682,407 +28660,407 @@ L 1015.902913 912.423837 - +" clip-path="url(#p547ed7124f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -29097,20 +29075,20 @@ L 1206.372448 905.441244 - - - + + + - + - + - + - + @@ -29119,20 +29097,20 @@ L 1216.160697 976.923785 - - - + + + - + - + - + - + @@ -29141,20 +29119,20 @@ L 1216.160697 942.571476 - - - + + + - + - + - + - + @@ -29165,407 +29143,407 @@ L 1216.160697 908.219168 - +" clip-path="url(#pe20cbf3836)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -29589,20 +29567,20 @@ L 205.083525 1003.205711 - - - + + + - + - + - + - + @@ -29611,20 +29589,20 @@ L 214.871775 1057.966601 - - - + + + - + - + - + - + @@ -29633,20 +29611,20 @@ L 214.871775 1037.72528 - - - + + + - + - + - + - + @@ -29657,407 +29635,407 @@ L 214.871775 1017.483959 - +" clip-path="url(#p576e56ba91)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - + - + @@ -30073,20 +30051,20 @@ L 405.34131 1003.205711 - - - + + + - + - + - + - + @@ -30095,20 +30073,20 @@ L 415.129559 1062.893756 - - - + + + - + - + - + - + @@ -30117,20 +30095,20 @@ L 415.129559 1042.683129 - - - + + + - + - + - + - + @@ -30141,407 +30119,407 @@ L 415.129559 1022.472503 - +" clip-path="url(#p406b44faae)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -30569,20 +30547,20 @@ L 605.599094 1003.205711 - - - + + + - + - + - + - + @@ -30591,20 +30569,20 @@ L 615.387344 1074.297049 - - - + + + - + - + - + - + @@ -30613,20 +30591,20 @@ L 615.387344 1042.412741 - - - + + + - + - + - + - + @@ -30637,407 +30615,407 @@ L 615.387344 1010.528433 - +" clip-path="url(#p7f0349015c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -31055,20 +31033,20 @@ L 805.856879 1003.205711 - - - + + + - + - + - + - + @@ -31077,20 +31055,20 @@ L 815.645128 1058.048639 - - - + + + - + - + - + - + @@ -31099,20 +31077,20 @@ L 815.645128 1036.183599 - - - + + + - + - + - + - + @@ -31123,407 +31101,407 @@ L 815.645128 1014.318559 - +" clip-path="url(#pc299e1824c)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -31534,20 +31512,20 @@ L 1006.114663 1003.205711 - - - + + + - + - + - + - + @@ -31556,20 +31534,20 @@ L 1015.902913 1075.415325 - - - + + + - + - + - + - + @@ -31578,20 +31556,20 @@ L 1015.902913 1044.429662 - - - + + + - + - + - + - + @@ -31602,407 +31580,407 @@ L 1015.902913 1013.444 - +" clip-path="url(#pb9b83018c5)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -32027,20 +32005,20 @@ L 1206.372448 1003.205711 - - - + + + - + - + - + - + @@ -32049,20 +32027,20 @@ L 1216.160697 1044.817291 - - - + + + - + - + - + - + @@ -32073,407 +32051,407 @@ L 1216.160697 1011.089216 - +" clip-path="url(#pb248cf268f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -32497,20 +32475,20 @@ L 205.083525 1102.282316 - - - + + + - + - + - + - + @@ -32519,20 +32497,20 @@ L 214.871775 1159.428538 - - - + + + - + - + - + - + @@ -32541,20 +32519,20 @@ L 214.871775 1140.37385 - - - + + + - + - + - + - + @@ -32565,407 +32543,407 @@ L 214.871775 1121.319162 - +" clip-path="url(#p825e56bd41)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -32986,20 +32964,20 @@ L 405.34131 1102.282316 - - - + + + - + - + - + - + @@ -33008,20 +32986,20 @@ L 415.129559 1160.988927 - - - + + + - + - + - + - + @@ -33030,20 +33008,20 @@ L 415.129559 1139.201737 - - - + + + - + - + - + - + @@ -33054,407 +33032,407 @@ L 415.129559 1117.414547 - +" clip-path="url(#p7086ab6a5e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -33479,20 +33457,20 @@ L 605.599094 1102.282316 - - - + + + - + - + - + - + @@ -33501,20 +33479,20 @@ L 615.387344 1175.618886 - - - + + + - + - + - + - + @@ -33523,20 +33501,20 @@ L 615.387344 1143.255394 - - - + + + - + - + - + - + @@ -33547,407 +33525,407 @@ L 615.387344 1110.891902 - +" clip-path="url(#p15d1fd9def)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -33962,20 +33940,20 @@ L 805.856879 1102.282316 - - - + + + - + - + - + - + @@ -33984,20 +33962,20 @@ L 815.645128 1140.87883 - - - + + + - + - + - + - + @@ -34008,407 +33986,407 @@ L 815.645128 1104.769682 - +" clip-path="url(#pc3a2137adb)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -34418,20 +34396,20 @@ L 1006.114663 1102.282316 - - - + + + - + - + - + - + @@ -34440,20 +34418,20 @@ L 1015.902913 1171.958418 - - - + + + - + - + - + - + @@ -34462,20 +34440,20 @@ L 1015.902913 1142.083182 - - - + + + - + - + - + - + @@ -34486,407 +34464,407 @@ L 1015.902913 1112.207947 - +" clip-path="url(#pf318e39781)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -34902,20 +34880,20 @@ L 1206.372448 1102.282316 - - - + + + - + - + - + - + @@ -34924,20 +34902,20 @@ L 1216.160697 1164.962414 - - - + + + - + - + - + - + @@ -34946,20 +34924,20 @@ L 1216.160697 1141.737196 - - - + + + - + - + - + - + @@ -34970,407 +34948,407 @@ L 1216.160697 1118.511977 - +" clip-path="url(#p1582e469bc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> + + + + + + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - - - - - - - + - - - - - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - + - + - + @@ -35387,20 +35365,42 @@ L 205.083525 1203.417233 + + + + + + + + + + + + + + + + + + + + - + - + - + @@ -35411,429 +35411,429 @@ L 214.871775 1245.062549 - + - + - - + + - - + + - +" clip-path="url(#p9ab62bcb26)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9ab62bcb26)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -35864,18 +35864,18 @@ L 405.34131 1203.417233 - + - + - + @@ -35886,18 +35886,18 @@ L 415.129559 1276.692966 - + - + - + @@ -35908,18 +35908,18 @@ L 415.129559 1243.428675 - + - + - + @@ -35930,407 +35930,407 @@ L 415.129559 1210.164384 - +" clip-path="url(#p8be97470dc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8be97470dc)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -36357,18 +36357,18 @@ L 605.599094 1203.417233 - + - + - + @@ -36379,18 +36379,18 @@ L 615.387344 1277.621303 - + - + - + @@ -36401,18 +36401,18 @@ L 615.387344 1242.716166 - + - + - + @@ -36423,407 +36423,407 @@ L 615.387344 1207.811028 - +" clip-path="url(#p35aae3e44f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p35aae3e44f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -36848,18 +36848,18 @@ L 805.856879 1203.417233 - + - + - + @@ -36870,18 +36870,18 @@ L 815.645128 1274.57208 - + - + - + @@ -36892,18 +36892,18 @@ L 815.645128 1240.434838 - + - + - + @@ -36914,407 +36914,407 @@ L 815.645128 1206.297595 - +" clip-path="url(#pcad7b6587e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#pcad7b6587e)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -37339,18 +37339,18 @@ L 1006.114663 1203.417233 - + - + - + @@ -37361,18 +37361,18 @@ L 1015.902913 1274.350116 - + - + - + @@ -37383,18 +37383,18 @@ L 1015.902913 1244.713437 - + - + - + @@ -37405,407 +37405,407 @@ L 1015.902913 1215.076758 - +" clip-path="url(#p43d1f496d0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p43d1f496d0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -37831,18 +37831,18 @@ L 1206.372448 1203.417233 - + - + - + @@ -37853,18 +37853,18 @@ L 1216.160697 1269.263355 - + - + - + @@ -37875,18 +37875,18 @@ L 1216.160697 1242.508442 - + - + - + @@ -37897,401 +37897,401 @@ L 1216.160697 1215.75353 - +" clip-path="url(#p1161f894f0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p1161f894f0)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -38319,18 +38319,18 @@ L 205.083525 1304.980918 - + - + - + @@ -38341,18 +38341,18 @@ L 214.871775 1368.951521 - + - + - + @@ -38363,18 +38363,18 @@ L 214.871775 1343.773716 - + - + - + @@ -38385,401 +38385,401 @@ L 214.871775 1318.595911 - +" clip-path="url(#p8122f36f1f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p8122f36f1f)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -38809,18 +38809,18 @@ L 405.34131 1304.980918 - + - + - + @@ -38831,18 +38831,18 @@ L 415.129559 1374.078671 - + - + - + @@ -38853,18 +38853,18 @@ L 415.129559 1346.585484 - + - + - + @@ -38875,304 +38875,304 @@ L 415.129559 1319.092297 - +" clip-path="url(#p9df0a0ac89)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - +" clip-path="url(#p9df0a0ac89)" style="fill: #d3d3d3; stroke: #000000; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - + - + - - - - - @@ -39180,80 +39180,80 @@ z - + - - - @@ -39271,32 +39271,32 @@ z - + - @@ -39317,58 +39317,58 @@ z - + - - @@ -39389,44 +39389,44 @@ z - + - - @@ -39459,82 +39459,82 @@ z - + - - - @@ -39576,40 +39576,40 @@ z - + - - - @@ -39641,78 +39641,78 @@ z - + - - - - @@ -39742,26 +39742,26 @@ z - + - @@ -39804,7 +39804,7 @@ z - + @@ -39819,12 +39819,12 @@ z - + - + @@ -39834,12 +39834,12 @@ z - + - + @@ -39848,23 +39848,23 @@ z - - - - @@ -40006,245 +40006,245 @@ L 1216.160697 1304.980918 - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + From 9360134fb82f34d04e1f680e19fe6dc637764ec9 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 11 Apr 2026 00:43:13 +0800 Subject: [PATCH 18/21] exclude svg from pre-commit --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ddc855375cf..167cc070057 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,6 +21,7 @@ repos: args: [--fix=lf] - id: trailing-whitespace name: "Remove trailing whitespace" + exclude: *.svg - id: file-contents-sorter name: "Sort codespell ignore list" From c7269af1f9ba02eafe6d51f22074dd73410762b3 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 11 Apr 2026 00:44:30 +0800 Subject: [PATCH 19/21] Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 167cc070057..b6f95ab0793 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: args: [--fix=lf] - id: trailing-whitespace name: "Remove trailing whitespace" - exclude: *.svg + exclude: .*\.svg - id: file-contents-sorter name: "Sort codespell ignore list" From df300e1773997c1298286b0b6b63d295b8b6dfc4 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Sat, 11 Apr 2026 01:04:30 +0100 Subject: [PATCH 20/21] Apply suggestions from code review Co-authored-by: Mark Shannon Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- peps/pep-0831.rst | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/peps/pep-0831.rst b/peps/pep-0831.rst index e69b444fc7f..d748a662742 100644 --- a/peps/pep-0831.rst +++ b/peps/pep-0831.rst @@ -29,7 +29,7 @@ This PEP proposes two things: with frame pointers by default.** This PEP recommends that *every* compiled component that participates in the Python call stack (C extensions, Rust extensions, embedding applications, and native libraries) should enable - frame pointers. A frame-pointer chain is only as complete as its weakest + frame pointers. A frame-pointer chain is only as strong as its weakest link: a single library without frame pointers breaks profiling, debugging, and tracing for the entire process. @@ -101,8 +101,8 @@ the entire call stack:: Stack unwinding is the process of walking this chain to reconstruct the call stack. Profilers do it to find out where the program is spending time; debuggers do it to show backtraces; crash handlers do it to produce useful -error reports. With frame pointers, unwinding is a simple pointer chase: read -``%rbp``, follow the link, repeat. It takes microseconds and requires no +error reports. With frame pointers, unwinding is a simply following pointers: read +``%rbp``, follow the link, repeat. It is very fast and requires no external data. At optimisation levels ``-O1`` and above, GCC and Clang omit frame pointers by @@ -322,15 +322,14 @@ BPF programs for production monitoring), frame pointers are the only viable unwinding mechanism because they are the only mechanism the kernel's built-in helpers support. -CPython's own documentation already states the recommended fix:: +:ref:`CPython's own documentation `__ already states the +recommended fix: For best results, Python should be compiled with - CFLAGS='-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer' + ``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` as this allows profilers to unwind using only the frame pointer and not on DWARF debug information. - -- docs.python.org/3/howto/perf_profiling.html - Production profiling tools echo this guidance. Grafana Pyroscope's troubleshooting documentation states: "If your profiles show many shallow stack traces, typically 1-2 frames deep, your binary might have been compiled without @@ -359,16 +358,14 @@ Distributions Are Waiting for Upstream Fedora 38 [#fedora38]_, Ubuntu 24.04 LTS [#ubuntu2404]_, and Arch Linux have all rebuilt their entire package trees with ``-fno-omit-frame-pointer --mno-omit-leaf-frame-pointer``. However, Ubuntu 24.04 LTS explicitly exempted -CPython:: +-mno-omit-leaf-frame-pointer``. However, Ubuntu 24.04 LTS +`explicitly exempted CPython +`__: In cases where the impact is high (such as the Python interpreter), we'll continue to omit frame pointers until this is addressed. - -- ubuntu.com/blog/ubuntu-performance-engineering-with- - frame-pointers-by-default - The result is a circular dependency: the runtime most in need of frame pointers for profiling is the one that major distributions leave without them, pending an upstream fix. Red Hat Enterprise Linux and CentOS Stream also disable frame @@ -395,7 +392,7 @@ The need for a continuous chain is precisely why the flags must propagate to extension builds. If only the interpreter has frame pointers but extensions do not, the chain is still broken at every C extension boundary. By adding the flags to ``CFLAGS`` as reported by ``sysconfig``, extension builds that consume -CPython's compiler flags (for example via ``pip install``, ``setuptools``, or +CPython's compiler flags (for example via ``pip install``, Setuptools, or ``python setup.py build``) will inherit frame pointers by default. Extensions and libraries with independent build systems still need to enable the same flags themselves for the frame-pointer chain to remain continuous. @@ -517,7 +514,7 @@ Ecosystem Impact Because the flags are in ``CFLAGS``, they propagate automatically to consumers that build against CPython's reported compiler flags, such as C extensions -built via ``pip``, ``setuptools``, or direct ``sysconfig`` queries. Those +built via pip, Setuptools, or direct ``sysconfig`` queries. Those consumers need take no additional action to benefit from this change. Not all compiled code in the Python ecosystem inherits CPython's ``CFLAGS``. From 3b8af0ad741a452cca49d52f806532465d9d9ffb Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Sat, 11 Apr 2026 01:23:16 +0100 Subject: [PATCH 21/21] Apply suggestions --- peps/pep-0831.rst | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/peps/pep-0831.rst b/peps/pep-0831.rst index d748a662742..91de45c4f4f 100644 --- a/peps/pep-0831.rst +++ b/peps/pep-0831.rst @@ -39,7 +39,8 @@ quickly and reliably. Omitting them (the compiler's default at ``-O1`` and above) prevents these tools from producing useful call stacks for Python processes, and undermines the perf trampoline support CPython shipped in 3.12. -The measured overhead is under 2% geometric mean for typical workloads. +The measured overhead is under 2% geometric mean for typical workloads +(see `Backwards Compatibility`_ for per-platform numbers). Multiple major Linux distributions, language runtimes, and Python ecosystem tools have already adopted this change. No existing PEP covers this topic; CPython issue `#96174`_ has been open since August 2022 without resolution. @@ -67,8 +68,10 @@ default experience for Python. The performance wins that profiling enables far outweigh the modest overhead of frame pointers. As Brendan Gregg notes: "I've seen frame pointers help find -performance wins ranging from 5% to 500%" [#gregg2024]_. A 0.5-2% overhead that -unlocks the ability to find 5-500% improvements is a favourable trade. +performance wins ranging from 5% to 500%" [#gregg2024]_. These wins come from +identifying hot paths in production systems; they are not about CPython's own +overhead, but about what profiling enables across the full stack. A 0.5-2% +overhead that unlocks such insights is a favourable trade. What Are Frame Pointers? ------------------------ @@ -79,7 +82,7 @@ arguments, and the address to return to when the function finishes. The **call stack** is the chain of all active stack frames: it records which function called which, all the way from ``main()`` to the function currently executing. -A **frame pointer** is a CPU register (``%rbp`` on x86-64, ``x29`` on AArch64) +A **frame pointer** is a CPU register (for example, ``%rbp`` on x86-64, ``x29`` on AArch64) that each function sets to point to the base of its own stack frame. Each frame also stores the *previous* frame pointer, creating a linked list through the entire call stack:: @@ -101,23 +104,24 @@ the entire call stack:: Stack unwinding is the process of walking this chain to reconstruct the call stack. Profilers do it to find out where the program is spending time; debuggers do it to show backtraces; crash handlers do it to produce useful -error reports. With frame pointers, unwinding is a simply following pointers: read -``%rbp``, follow the link, repeat. It is very fast and requires no -external data. +error reports. With frame pointers, unwinding is simply following pointers: read +``%rbp``, follow the link, repeat. It requires no external data. At optimisation levels ``-O1`` and above, GCC and Clang omit frame pointers by default [#gcc_fomit]_. This frees the ``%rbp`` register for general use, giving the optimiser one more register to work with. On x86-64 this is a gain of one register out of 16 (about 7%). The performance benefit is small -(typically 0.5-2%) but it was considered worthwhile when the convention was -established for 32-bit x86, where the gain was one register out of 6 (~20%). +(typically a few percent) but it was considered worthwhile when the convention +was established for 32-bit x86, where the gain was one register out of 6 +(~20%). See `Detailed Performance Analysis of CPython with Frame Pointers`_ +for a full breakdown by platform and workload. Without frame pointers, the linked list does not exist. Tools that need to walk the call stack must instead parse DWARF debug information (a complex, -variable-length encoding of how each function laid out its stack frame). This -is slower, more fragile, and impossible in some contexts (such as inside the -Linux kernel). In the worst case, tools simply produce broken or incomplete -results. +variable-length encoding of how each function laid out its stack frame) or, +on Windows, ``.pdata`` / ``.xdata`` unwind metadata. This is slower, more +fragile, and impossible in some contexts (such as inside the Linux kernel). +In the worst case, tools simply produce broken or incomplete results. Here is a concrete example. A ``perf`` profile of a Python process **without** frame pointers typically shows:: @@ -322,8 +326,7 @@ BPF programs for production monitoring), frame pointers are the only viable unwinding mechanism because they are the only mechanism the kernel's built-in helpers support. -:ref:`CPython's own documentation `__ already states the -recommended fix: +CPython's own documentation already states the recommended fix: For best results, Python should be compiled with ``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` @@ -393,7 +396,7 @@ extension builds. If only the interpreter has frame pointers but extensions do not, the chain is still broken at every C extension boundary. By adding the flags to ``CFLAGS`` as reported by ``sysconfig``, extension builds that consume CPython's compiler flags (for example via ``pip install``, Setuptools, or -``python setup.py build``) will inherit frame pointers by default. Extensions +other build backends) will inherit frame pointers by default. Extensions and libraries with independent build systems still need to enable the same flags themselves for the frame-pointer chain to remain continuous. @@ -476,7 +479,7 @@ Using ``CFLAGS`` ensures: the ``python`` binary, ``libpython``, and built-in extension modules under ``Modules/``. 2. The flags **are** written into the ``sysconfig`` data, so that third-party C - extensions built against this Python (via ``pip``, ``setuptools``, or direct + extensions built against this Python (via ``pip``, Setuptools, or direct ``sysconfig`` queries) inherit frame pointers by default. This is an intentional design choice. For profiling data to be useful, the @@ -514,7 +517,7 @@ Ecosystem Impact Because the flags are in ``CFLAGS``, they propagate automatically to consumers that build against CPython's reported compiler flags, such as C extensions -built via pip, Setuptools, or direct ``sysconfig`` queries. Those +built via ``pip``, Setuptools, or direct ``sysconfig`` queries. Those consumers need take no additional action to benefit from this change. Not all compiled code in the Python ecosystem inherits CPython's ``CFLAGS``. @@ -522,7 +525,7 @@ Rust extensions built with ``pyo3`` or ``maturin``, C++ libraries with their own build systems, and embedding applications that compile CPython from source each manage their own compiler flags. This PEP recommends that all such projects also enable ``-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer`` -in their builds. A frame-pointer chain is only as complete as its weakest +in their builds. A frame-pointer chain is only as strong as its weakest link: a single library in the call stack without frame pointers breaks the chain for the entire process, regardless of whether CPython and every other library has them. The goal is that every native component in a Python process @@ -838,7 +841,7 @@ Machine Geometric mean effect ===================================== ======================= Apple M2 Mac Mini (arm64) 0.1% faster macOS M3 Pro (arm64) 0.1% slower -Raspberry Pi (aarch64). 0.2% slower +Raspberry Pi (aarch64) 0.2% slower Ampere Altra Max (aarch64) 0.9% faster AWS Graviton c7g.16xlarge (aarch64) 0.8% slower Intel i7 12700H (x86-64) 1.9% slower @@ -1053,7 +1056,7 @@ Footnotes https://github.com/Fidget-Spinner/python-framepointer-bench .. [#missing_benchmarks] Some benchmarks are missing due to incompatibilities with - Python 3.15alpha. + Python 3.15 alpha. .. _#96174: https://github.com/python/cpython/issues/96174 .. _python/cpython issue #96174: https://github.com/python/cpython/issues/96174 @@ -1065,7 +1068,7 @@ Appendix For all graphs below, the green dots are geometric means of the individual benchmark's median, while orange lines are the median of our data points. -Hollow circles reperesent outliers. +Hollow circles represent outliers. The first graph is the overall effect on pyperformance seen on each system. All system configurations have below 2% geometric mean and median slowdown: