Repository: ansible/ansible

Issue:
 Ansible startup performance slow due to time spent loading in ConfigManager
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
- Feature Idea
 
##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.1.0
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Linux pine64 3.10.104-2-pine64-longsleep #113 SMP PREEMPT Thu Dec 15 21:46:07 CET 2016 aarch64 aarch64 aarch64 GNU/Linux

##### SUMMARY
<!--- Explain the problem briefly -->
Ansible startup performance on (slow) test system 10 sec. mainly due to parsing of ansible/config/base.yml.
Could be reduced by patching ansible/config/manager.py, and adding 
`yaml.SafeLoader = yaml.CSafeLoader`
before 
`yaml.safe_load(config_def) `
is invoked.
Reduces startup time to 1/3rd of initial time.

I checked pyyaml if CSafeLoader can be forced as a default one way or another, 
and after a quick check, I didn't find a possibility to set a default loader (except with extra parameter)
(https://github.com/yaml/pyyaml/blob/master/lib/yaml/__init__.py)

Is it possible to have the CSafeLoader as the default behaviour when running ansible?

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Just run ansible executable

<!--- Paste example playbooks or commands between quotes below -->
```yaml

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```

```



Discussion:
@Hercules888 Could you retest with the AnsibleLoader class?

`from ansible.parsing.yaml.loader import AnsibleLoader`

If that retains the same performance as csafeloader, could you submit a PR?

Thanks for digging into this, it's very much appreciated.

Resolving patch:
diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py
--- a/lib/ansible/config/manager.py
+++ b/lib/ansible/config/manager.py
@@ -7,10 +7,16 @@
 import os
 import sys
 import tempfile
-import yaml
 
 from collections import namedtuple
 
+from yaml import load as yaml_load
+try:
+    # use C version if possible for speedup
+    from yaml import CSafeLoader as SafeLoader
+except ImportError:
+    from yaml import SafeLoader
+
 from ansible.config.data import ConfigData
 from ansible.errors import AnsibleOptionsError, AnsibleError
 from ansible.module_utils.six import string_types
@@ -181,7 +187,7 @@ def __init__(self, conf_file=None, defs_file=None):
         # consume definitions
         if os.path.exists(b_defs_file):
             with open(b_defs_file, 'rb') as config_def:
-                self._base_defs = yaml.safe_load(config_def)
+                self._base_defs = yaml_load(config_def, Loader=SafeLoader)
         else:
             raise AnsibleError("Missing base configuration definition file (bad install?): %s" % to_native(b_defs_file))
 


Test patch: