Skip to content

Commit

Permalink
scripts: edtlib/extract_dts_includes.py: Speed up 2x+ with yaml.CLoader
Browse files Browse the repository at this point in the history
Use the LibYAML-based yaml.CLoader if available instead of yaml.Loader,
which is written in Python and slow. See
https://pyyaml.org/wiki/PyYAMLDocumentation.

This speeds up gen_defines.py from 0.2s to 0.07s on my system, for
-DBOARD=hifive1. It should also make scripts/kconfig/kconfig.py faster,
because it indirectly uses edtlib via
scripts/kconfig/kconfigfunctions.py.

yaml.CLoader seems to be available out of the box when installing with
pip on Ubuntu at least.

Helps with zephyrproject-rtos#20104.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
  • Loading branch information
ulfalizer committed Oct 29, 2019
1 parent 86bf182 commit b820872
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 14 deletions.
22 changes: 13 additions & 9 deletions scripts/dts/edtlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
import sys

import yaml
try:
# Use the C LibYAML parser if available, rather than the Python parser.
# This makes e.g. gen_defines.py more than twice as fast.
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader

from dtlib import DT, DTError, to_num, to_nums, TYPE_EMPTY, TYPE_NUMS, \
TYPE_PHANDLE, TYPE_PHANDLES_AND_NUMS
Expand Down Expand Up @@ -168,10 +174,10 @@ def _init_compat2binding(self, bindings_dirs):
# Only bindings for 'compatible' strings that appear in the devicetree
# are loaded.

# Add legacy '!include foo.yaml' handling. Do
# yaml.Loader.add_constructor() instead of yaml.add_constructor() to be
# compatible with both version 3.13 and version 5.1 of PyYAML.
yaml.Loader.add_constructor("!include", _binding_include)
# Add legacy '!include foo.yaml' handling. Do Loader.add_constructor()
# instead of yaml.add_constructor() to be compatible with both version
# 3.13 and version 5.1 of PyYAML.
Loader.add_constructor("!include", _binding_include)

dt_compats = _dt_compats(self._dt)
# Searches for any 'compatible' string mentioned in the devicetree
Expand All @@ -188,9 +194,7 @@ def _init_compat2binding(self, bindings_dirs):
contents = f.read()

# As an optimization, skip parsing files that don't contain any of
# the .dts 'compatible' strings, which should be reasonably safe.
# This optimization shaves 5+ seconds off 'cmake' configuration
# time on my system. Using yaml.CParser would probably help too.
# the .dts 'compatible' strings, which should be reasonably safe
if not dt_compats_search(contents):
continue

Expand All @@ -201,7 +205,7 @@ def _init_compat2binding(self, bindings_dirs):
try:
# Parsed PyYAML output (Python lists/dictionaries/strings/etc.,
# representing the file)
binding = yaml.load(contents, Loader=yaml.Loader)
binding = yaml.load(contents, Loader=Loader)
except yaml.YAMLError as e:
self._warn("'{}' appears in binding directories but isn't "
"valid YAML: {}".format(binding_path, e))
Expand Down Expand Up @@ -367,7 +371,7 @@ def _load_binding(self, fname):

with open(paths[0], encoding="utf-8") as f:
return self._merge_included_bindings(
yaml.load(f, Loader=yaml.Loader),
yaml.load(f, Loader=Loader),
paths[0])

def _init_nodes(self):
Expand Down
17 changes: 12 additions & 5 deletions scripts/dts/extract_dts_includes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@

import os, fnmatch
import re
import yaml
import argparse
from collections import defaultdict

import yaml
try:
# Use the C LibYAML parser if available, rather than the Python parser.
# It's much faster.
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader

from devicetree import parse_file
from extract.globals import *
import extract.globals
Expand Down Expand Up @@ -336,7 +343,7 @@ def load_bindings(root, binding_dirs):
compats = []

# Add '!include foo.yaml' handling
yaml.Loader.add_constructor('!include', yaml_include)
Loader.add_constructor('!include', yaml_include)

# Code below is adapated from edtlib.py

Expand All @@ -353,15 +360,15 @@ def load_bindings(root, binding_dirs):
if not dt_compats_search(contents):
continue

binding = yaml.load(contents, Loader=yaml.Loader)
binding = yaml.load(contents, Loader=Loader)

binding_compats = _binding_compats(binding)
if not binding_compats:
continue

with open(file, 'r', encoding='utf-8') as yf:
binding = merge_included_bindings(file,
yaml.load(yf, Loader=yaml.Loader))
yaml.load(yf, Loader=Loader))

for compat in binding_compats:
if compat not in compats:
Expand Down Expand Up @@ -456,7 +463,7 @@ def load_binding_file(fname):
"!include statement: {}".format(fname, filepaths))

with open(filepaths[0], 'r', encoding='utf-8') as f:
return yaml.load(f, Loader=yaml.Loader)
return yaml.load(f, Loader=Loader)


def yaml_inc_error(msg):
Expand Down

0 comments on commit b820872

Please sign in to comment.