├── rebar.lock ├── rebar.config ├── benchmark ├── eenv_mock.erl ├── eenv_benchmark.hrl ├── eenv_mock_ssl.erl └── eenv_benchmark.erl ├── src ├── eenv.app.src └── eenv.erl ├── .travis.yml ├── LICENSE ├── Makefile └── README.md /rebar.lock: -------------------------------------------------------------------------------- 1 | []. 2 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [report_errors, report_warnings]}. 2 | {deps, []}. -------------------------------------------------------------------------------- /benchmark/eenv_mock.erl: -------------------------------------------------------------------------------- 1 | -module(eenv_mock). 2 | 3 | %% API 4 | -export([get/2]). 5 | 6 | get(ssl, Key) -> 7 | eenv_mock_ssl:get(Key); 8 | get(_, _) -> 9 | unload. 10 | -------------------------------------------------------------------------------- /src/eenv.app.src: -------------------------------------------------------------------------------- 1 | {application, eenv, 2 | [{description, "Application Configuration Manager"}, 3 | {vsn, "0.1.1"}, 4 | {registered, []}, 5 | {applications, 6 | [kernel, stdlib]}, 7 | {env, []}, 8 | {modules, []}, 9 | {maintainers, ["zhongwencool"]}, 10 | {licenses, ["MIT"]}, 11 | {links, [{"Github", "https://github.com/zhongwencool/erl-env"}]} 12 | ]}. 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | otp_release: 3 | - 20.1 4 | - 19.3 5 | - 18.3 6 | - 17.5 7 | - R16B03-1 8 | - R15B03 9 | 10 | env: 11 | - PATH=$HOME/.cache/rebar3/bin/:$PATH 12 | 13 | before_script: 14 | - curl -O -L https://s3.amazonaws.com/rebar3/rebar3 15 | - chmod +x rebar3 16 | - ./rebar3 update 17 | 18 | script: "rm -rf deps ebin test/*.beam logs && ./rebar3 compile" 19 | 20 | branches: 21 | only: 22 | - master 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 某文 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | REBAR = $(shell which rebar3) 3 | 4 | .PHONY: help check_rebar compile clean distclean dialyzer benchmark5000 benchmark10000 benchmark50000 5 | 6 | help: ## Show this help. 7 | @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST) 8 | 9 | check_rebar: 10 | ifeq ($(REBAR),) 11 | ifeq ($(wildcard rebar3),) 12 | curl -O https://s3.amazonaws.com/rebar3/rebar3 13 | chmod a+x rebar3 14 | ./rebar3 update 15 | $(eval REBAR=./rebar3) 16 | else 17 | $(eval REBAR=./rebar3) 18 | endif 19 | endif 20 | 21 | compile: check_rebar ## same as rebar3 compile 22 | @$(REBAR) compile 23 | 24 | eunit: check_rebar ## same as rebar3 eunit 25 | @$(REBAR) eunit 26 | 27 | dialyzer: check_rebar ## rebar3 dialyzer 28 | $(REBAR) dialyzer 29 | 30 | distclean: clean ## clean all 31 | @echo "rm -rf _build *.dump *_plt *.crashdump..." 32 | $(REBAR) clean --all 33 | rm -rf _build *.dump *_plt *.crashdump 34 | 35 | shell: perpare ## rebar3 shell 36 | $(REBAR) shell 37 | 38 | benchmark: perpare ## make benchmark 10000 chart 39 | @echo "Starting benchmark..." 40 | @erl -pa _build/default/lib/eenv/ebin -smp -eval "eenv_benchmark:test(10000), halt(0)" 41 | 42 | benchmark5000: perpare ## make benchmark 5000 chart 43 | @echo "Starting benchmark count:5000..." 44 | @erl -pa _build/default/lib/eenv/ebin -smp -eval "eenv_benchmark:test(5000), halt(0)" 45 | 46 | benchmark50000: perpare ## make benchmark 50000 chart 47 | @echo "Starting benchmark count:50000..." 48 | @erl -pa _build/default/lib/eenv/ebin -smp -eval "eenv_benchmark:test(50000), halt(0)" 49 | 50 | perpare: compile 51 | @cd benchmark && erlc -o ../_build/default/lib/eenv/ebin *.erl && cd .. 52 | 53 | #####COLORS####### 54 | GREEN := $(shell tput -Txterm setaf 2) 55 | WHITE := $(shell tput -Txterm setaf 7) 56 | YELLOW := $(shell tput -Txterm setaf 3) 57 | RESET := $(shell tput -Txterm sgr0) 58 | 59 | # Add the following 'help' target to your Makefile 60 | # And add help text after each target name starting with '\#\#' 61 | # A category can be added with @category 62 | HELP_FUN = \ 63 | %help; \ 64 | while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \ 65 | print "usage: make [target]\n\n"; \ 66 | for (sort keys %help) { \ 67 | print "${WHITE}$$_:${RESET}\n"; \ 68 | for (@{$$help{$$_}}) { \ 69 | $$sep = " " x (32 - length $$_->[0]); \ 70 | print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \ 71 | }; \ 72 | print "\n"; } 73 | -------------------------------------------------------------------------------- /benchmark/eenv_benchmark.hrl: -------------------------------------------------------------------------------- 1 | -record(rec, 2 | {test_par99 = {ok, test_val}, 3 | test_par98 = {ok, test_val}, 4 | test_par97 = {ok, test_val}, 5 | test_par96 = {ok, test_val}, 6 | test_par95 = {ok, test_val}, 7 | test_par94 = {ok, test_val}, 8 | test_par93 = {ok, test_val}, 9 | test_par92 = {ok, test_val}, 10 | test_par91 = {ok, test_val}, 11 | test_par90 = {ok, test_val}, 12 | test_par9 = {ok, test_val}, 13 | test_par89 = {ok, test_val}, 14 | test_par88 = {ok, test_val}, 15 | test_par87 = {ok, test_val}, 16 | test_par86 = {ok, test_val}, 17 | test_par85 = {ok, test_val}, 18 | test_par84 = {ok, test_val}, 19 | test_par83 = {ok, test_val}, 20 | test_par82 = {ok, test_val}, 21 | test_par81 = {ok, test_val}, 22 | test_par80 = {ok, test_val}, 23 | test_par8 = {ok, test_val}, 24 | test_par79 = {ok, test_val}, 25 | test_par78 = {ok, test_val}, 26 | test_par77 = {ok, test_val}, 27 | test_par76 = {ok, test_val}, 28 | test_par75 = {ok, test_val}, 29 | test_par74 = {ok, test_val}, 30 | test_par73 = {ok, test_val}, 31 | test_par72 = {ok, test_val}, 32 | test_par71 = {ok, test_val}, 33 | test_par70 = {ok, test_val}, 34 | test_par7 = {ok, test_val}, 35 | test_par69 = {ok, test_val}, 36 | test_par68 = {ok, test_val}, 37 | test_par67 = {ok, test_val}, 38 | test_par66 = {ok, test_val}, 39 | test_par65 = {ok, test_val}, 40 | test_par64 = {ok, test_val}, 41 | test_par63 = {ok, test_val}, 42 | test_par62 = {ok, test_val}, 43 | test_par61 = {ok, test_val}, 44 | test_par60 = {ok, test_val}, 45 | test_par6 = {ok, test_val}, 46 | test_par59 = {ok, test_val}, 47 | test_par58 = {ok, test_val}, 48 | test_par57 = {ok, test_val}, 49 | test_par56 = {ok, test_val}, 50 | test_par55 = {ok, test_val}, 51 | test_par54 = {ok, test_val}, 52 | test_par53 = {ok, test_val}, 53 | test_par52 = {ok, test_val}, 54 | test_par51 = {ok, test_val}, 55 | test_par50 = {ok, test_val}, 56 | test_par5 = {ok, test_val}, 57 | test_par49 = {ok, test_val}, 58 | test_par48 = {ok, test_val}, 59 | test_par47 = {ok, test_val}, 60 | test_par46 = {ok, test_val}, 61 | test_par45 = {ok, test_val}, 62 | test_par44 = {ok, test_val}, 63 | test_par43 = {ok, test_val}, 64 | test_par42 = {ok, test_val}, 65 | test_par41 = {ok, test_val}, 66 | test_par40 = {ok, test_val}, 67 | test_par4 = {ok, test_val}, 68 | test_par39 = {ok, test_val}, 69 | test_par38 = {ok, test_val}, 70 | test_par37 = {ok, test_val}, 71 | test_par36 = {ok, test_val}, 72 | test_par35 = {ok, test_val}, 73 | test_par34 = {ok, test_val}, 74 | test_par33 = {ok, test_val}, 75 | test_par32 = {ok, test_val}, 76 | test_par31 = {ok, test_val}, 77 | test_par30 = {ok, test_val}, 78 | test_par3 = {ok, test_val}, 79 | test_par29 = {ok, test_val}, 80 | test_par28 = {ok, test_val}, 81 | test_par27 = {ok, test_val}, 82 | test_par26 = {ok, test_val}, 83 | test_par25 = {ok, test_val}, 84 | test_par24 = {ok, test_val}, 85 | test_par23 = {ok, test_val}, 86 | test_par22 = {ok, test_val}, 87 | test_par21 = {ok, test_val}, 88 | test_par200 = {ok, test_val}, 89 | test_par20 = {ok, test_val}, 90 | test_par2 = {ok, test_val}, 91 | test_par199 = {ok, test_val}, 92 | test_par198 = {ok, test_val}, 93 | test_par197 = {ok, test_val}, 94 | test_par196 = {ok, test_val}, 95 | test_par195 = {ok, test_val}, 96 | test_par194 = {ok, test_val}, 97 | test_par193 = {ok, test_val}, 98 | test_par192 = {ok, test_val}, 99 | test_par191 = {ok, test_val}, 100 | test_par190 = {ok, test_val}, 101 | test_par19 = {ok, test_val}, 102 | test_par189 = {ok, test_val}, 103 | test_par188 = {ok, test_val}, 104 | test_par187 = {ok, test_val}, 105 | test_par186 = {ok, test_val}, 106 | test_par185 = {ok, test_val}, 107 | test_par184 = {ok, test_val}, 108 | test_par183 = {ok, test_val}, 109 | test_par182 = {ok, test_val}, 110 | test_par181 = {ok, test_val}, 111 | test_par180 = {ok, test_val}, 112 | test_par18 = {ok, test_val}, 113 | test_par179 = {ok, test_val}, 114 | test_par178 = {ok, test_val}, 115 | test_par177 = {ok, test_val}, 116 | test_par176 = {ok, test_val}, 117 | test_par175 = {ok, test_val}, 118 | test_par174 = {ok, test_val}, 119 | test_par173 = {ok, test_val}, 120 | test_par172 = {ok, test_val}, 121 | test_par171 = {ok, test_val}, 122 | test_par170 = {ok, test_val}, 123 | test_par17 = {ok, test_val}, 124 | test_par169 = {ok, test_val}, 125 | test_par168 = {ok, test_val}, 126 | test_par167 = {ok, test_val}, 127 | test_par166 = {ok, test_val}, 128 | test_par165 = {ok, test_val}, 129 | test_par164 = {ok, test_val}, 130 | test_par163 = {ok, test_val}, 131 | test_par162 = {ok, test_val}, 132 | test_par161 = {ok, test_val}, 133 | test_par160 = {ok, test_val}, 134 | test_par16 = {ok, test_val}, 135 | test_par159 = {ok, test_val}, 136 | test_par158 = {ok, test_val}, 137 | test_par157 = {ok, test_val}, 138 | test_par156 = {ok, test_val}, 139 | test_par155 = {ok, test_val}, 140 | test_par154 = {ok, test_val}, 141 | test_par153 = {ok, test_val}, 142 | test_par152 = {ok, test_val}, 143 | test_par151 = {ok, test_val}, 144 | test_par150 = {ok, test_val}, 145 | test_par15 = {ok, test_val}, 146 | test_par149 = {ok, test_val}, 147 | test_par148 = {ok, test_val}, 148 | test_par147 = {ok, test_val}, 149 | test_par146 = {ok, test_val}, 150 | test_par145 = {ok, test_val}, 151 | test_par144 = {ok, test_val}, 152 | test_par143 = {ok, test_val}, 153 | test_par142 = {ok, test_val}, 154 | test_par141 = {ok, test_val}, 155 | test_par140 = {ok, test_val}, 156 | test_par14 = {ok, test_val}, 157 | test_par139 = {ok, test_val}, 158 | test_par138 = {ok, test_val}, 159 | test_par137 = {ok, test_val}, 160 | test_par136 = {ok, test_val}, 161 | test_par135 = {ok, test_val}, 162 | test_par134 = {ok, test_val}, 163 | test_par133 = {ok, test_val}, 164 | test_par132 = {ok, test_val}, 165 | test_par131 = {ok, test_val}, 166 | test_par130 = {ok, test_val}, 167 | test_par13 = {ok, test_val}, 168 | test_par129 = {ok, test_val}, 169 | test_par128 = {ok, test_val}, 170 | test_par127 = {ok, test_val}, 171 | test_par126 = {ok, test_val}, 172 | test_par125 = {ok, test_val}, 173 | test_par124 = {ok, test_val}, 174 | test_par123 = {ok, test_val}, 175 | test_par122 = {ok, test_val}, 176 | test_par121 = {ok, test_val}, 177 | test_par120 = {ok, test_val}, 178 | test_par12 = {ok, test_val}, 179 | test_par119 = {ok, test_val}, 180 | test_par118 = {ok, test_val}, 181 | test_par117 = {ok, test_val}, 182 | test_par116 = {ok, test_val}, 183 | test_par115 = {ok, test_val}, 184 | test_par114 = {ok, test_val}, 185 | test_par113 = {ok, test_val}, 186 | test_par112 = {ok, test_val}, 187 | test_par111 = {ok, test_val}, 188 | test_par110 = {ok, test_val}, 189 | test_par11 = {ok, test_val}, 190 | test_par109 = {ok, test_val}, 191 | test_par108 = {ok, test_val}, 192 | test_par107 = {ok, test_val}, 193 | test_par106 = {ok, test_val}, 194 | test_par105 = {ok, test_val}, 195 | test_par104 = {ok, test_val}, 196 | test_par103 = {ok, test_val}, 197 | test_par102 = {ok, test_val}, 198 | test_par101 = {ok, test_val}, 199 | test_par100 = {ok, test_val}, 200 | test_par10 = {ok, test_val}, 201 | test_par1 = {ok, test_val} 202 | }). 203 | -------------------------------------------------------------------------------- /benchmark/eenv_mock_ssl.erl: -------------------------------------------------------------------------------- 1 | -module(eenv_mock_ssl). 2 | 3 | -export([get/1]). 4 | get(test_par99) -> {ok, test_val}; 5 | get(test_par98) -> {ok, test_val}; 6 | get(test_par97) -> {ok, test_val}; 7 | get(test_par96) -> {ok, test_val}; 8 | get(test_par95) -> {ok, test_val}; 9 | get(test_par94) -> {ok, test_val}; 10 | get(test_par93) -> {ok, test_val}; 11 | get(test_par92) -> {ok, test_val}; 12 | get(test_par91) -> {ok, test_val}; 13 | get(test_par90) -> {ok, test_val}; 14 | get(test_par9) -> {ok, test_val}; 15 | get(test_par89) -> {ok, test_val}; 16 | get(test_par88) -> {ok, test_val}; 17 | get(test_par87) -> {ok, test_val}; 18 | get(test_par86) -> {ok, test_val}; 19 | get(test_par85) -> {ok, test_val}; 20 | get(test_par84) -> {ok, test_val}; 21 | get(test_par83) -> {ok, test_val}; 22 | get(test_par82) -> {ok, test_val}; 23 | get(test_par81) -> {ok, test_val}; 24 | get(test_par80) -> {ok, test_val}; 25 | get(test_par8) -> {ok, test_val}; 26 | get(test_par79) -> {ok, test_val}; 27 | get(test_par78) -> {ok, test_val}; 28 | get(test_par77) -> {ok, test_val}; 29 | get(test_par76) -> {ok, test_val}; 30 | get(test_par75) -> {ok, test_val}; 31 | get(test_par74) -> {ok, test_val}; 32 | get(test_par73) -> {ok, test_val}; 33 | get(test_par72) -> {ok, test_val}; 34 | get(test_par71) -> {ok, test_val}; 35 | get(test_par70) -> {ok, test_val}; 36 | get(test_par7) -> {ok, test_val}; 37 | get(test_par69) -> {ok, test_val}; 38 | get(test_par68) -> {ok, test_val}; 39 | get(test_par67) -> {ok, test_val}; 40 | get(test_par66) -> {ok, test_val}; 41 | get(test_par65) -> {ok, test_val}; 42 | get(test_par64) -> {ok, test_val}; 43 | get(test_par63) -> {ok, test_val}; 44 | get(test_par62) -> {ok, test_val}; 45 | get(test_par61) -> {ok, test_val}; 46 | get(test_par60) -> {ok, test_val}; 47 | get(test_par6) -> {ok, test_val}; 48 | get(test_par59) -> {ok, test_val}; 49 | get(test_par58) -> {ok, test_val}; 50 | get(test_par57) -> {ok, test_val}; 51 | get(test_par56) -> {ok, test_val}; 52 | get(test_par55) -> {ok, test_val}; 53 | get(test_par54) -> {ok, test_val}; 54 | get(test_par53) -> {ok, test_val}; 55 | get(test_par52) -> {ok, test_val}; 56 | get(test_par51) -> {ok, test_val}; 57 | get(test_par50) -> {ok, test_val}; 58 | get(test_par5) -> {ok, test_val}; 59 | get(test_par49) -> {ok, test_val}; 60 | get(test_par48) -> {ok, test_val}; 61 | get(test_par47) -> {ok, test_val}; 62 | get(test_par46) -> {ok, test_val}; 63 | get(test_par45) -> {ok, test_val}; 64 | get(test_par44) -> {ok, test_val}; 65 | get(test_par43) -> {ok, test_val}; 66 | get(test_par42) -> {ok, test_val}; 67 | get(test_par41) -> {ok, test_val}; 68 | get(test_par40) -> {ok, test_val}; 69 | get(test_par4) -> {ok, test_val}; 70 | get(test_par39) -> {ok, test_val}; 71 | get(test_par38) -> {ok, test_val}; 72 | get(test_par37) -> {ok, test_val}; 73 | get(test_par36) -> {ok, test_val}; 74 | get(test_par35) -> {ok, test_val}; 75 | get(test_par34) -> {ok, test_val}; 76 | get(test_par33) -> {ok, test_val}; 77 | get(test_par32) -> {ok, test_val}; 78 | get(test_par31) -> {ok, test_val}; 79 | get(test_par30) -> {ok, test_val}; 80 | get(test_par3) -> {ok, test_val}; 81 | get(test_par29) -> {ok, test_val}; 82 | get(test_par28) -> {ok, test_val}; 83 | get(test_par27) -> {ok, test_val}; 84 | get(test_par26) -> {ok, test_val}; 85 | get(test_par25) -> {ok, test_val}; 86 | get(test_par24) -> {ok, test_val}; 87 | get(test_par23) -> {ok, test_val}; 88 | get(test_par22) -> {ok, test_val}; 89 | get(test_par21) -> {ok, test_val}; 90 | get(test_par200) -> {ok, test_val}; 91 | get(test_par20) -> {ok, test_val}; 92 | get(test_par2) -> {ok, test_val}; 93 | get(test_par199) -> {ok, test_val}; 94 | get(test_par198) -> {ok, test_val}; 95 | get(test_par197) -> {ok, test_val}; 96 | get(test_par196) -> {ok, test_val}; 97 | get(test_par195) -> {ok, test_val}; 98 | get(test_par194) -> {ok, test_val}; 99 | get(test_par193) -> {ok, test_val}; 100 | get(test_par192) -> {ok, test_val}; 101 | get(test_par191) -> {ok, test_val}; 102 | get(test_par190) -> {ok, test_val}; 103 | get(test_par19) -> {ok, test_val}; 104 | get(test_par189) -> {ok, test_val}; 105 | get(test_par188) -> {ok, test_val}; 106 | get(test_par187) -> {ok, test_val}; 107 | get(test_par186) -> {ok, test_val}; 108 | get(test_par185) -> {ok, test_val}; 109 | get(test_par184) -> {ok, test_val}; 110 | get(test_par183) -> {ok, test_val}; 111 | get(test_par182) -> {ok, test_val}; 112 | get(test_par181) -> {ok, test_val}; 113 | get(test_par180) -> {ok, test_val}; 114 | get(test_par18) -> {ok, test_val}; 115 | get(test_par179) -> {ok, test_val}; 116 | get(test_par178) -> {ok, test_val}; 117 | get(test_par177) -> {ok, test_val}; 118 | get(test_par176) -> {ok, test_val}; 119 | get(test_par175) -> {ok, test_val}; 120 | get(test_par174) -> {ok, test_val}; 121 | get(test_par173) -> {ok, test_val}; 122 | get(test_par172) -> {ok, test_val}; 123 | get(test_par171) -> {ok, test_val}; 124 | get(test_par170) -> {ok, test_val}; 125 | get(test_par17) -> {ok, test_val}; 126 | get(test_par169) -> {ok, test_val}; 127 | get(test_par168) -> {ok, test_val}; 128 | get(test_par167) -> {ok, test_val}; 129 | get(test_par166) -> {ok, test_val}; 130 | get(test_par165) -> {ok, test_val}; 131 | get(test_par164) -> {ok, test_val}; 132 | get(test_par163) -> {ok, test_val}; 133 | get(test_par162) -> {ok, test_val}; 134 | get(test_par161) -> {ok, test_val}; 135 | get(test_par160) -> {ok, test_val}; 136 | get(test_par16) -> {ok, test_val}; 137 | get(test_par159) -> {ok, test_val}; 138 | get(test_par158) -> {ok, test_val}; 139 | get(test_par157) -> {ok, test_val}; 140 | get(test_par156) -> {ok, test_val}; 141 | get(test_par155) -> {ok, test_val}; 142 | get(test_par154) -> {ok, test_val}; 143 | get(test_par153) -> {ok, test_val}; 144 | get(test_par152) -> {ok, test_val}; 145 | get(test_par151) -> {ok, test_val}; 146 | get(test_par150) -> {ok, test_val}; 147 | get(test_par15) -> {ok, test_val}; 148 | get(test_par149) -> {ok, test_val}; 149 | get(test_par148) -> {ok, test_val}; 150 | get(test_par147) -> {ok, test_val}; 151 | get(test_par146) -> {ok, test_val}; 152 | get(test_par145) -> {ok, test_val}; 153 | get(test_par144) -> {ok, test_val}; 154 | get(test_par143) -> {ok, test_val}; 155 | get(test_par142) -> {ok, test_val}; 156 | get(test_par141) -> {ok, test_val}; 157 | get(test_par140) -> {ok, test_val}; 158 | get(test_par14) -> {ok, test_val}; 159 | get(test_par139) -> {ok, test_val}; 160 | get(test_par138) -> {ok, test_val}; 161 | get(test_par137) -> {ok, test_val}; 162 | get(test_par136) -> {ok, test_val}; 163 | get(test_par135) -> {ok, test_val}; 164 | get(test_par134) -> {ok, test_val}; 165 | get(test_par133) -> {ok, test_val}; 166 | get(test_par132) -> {ok, test_val}; 167 | get(test_par131) -> {ok, test_val}; 168 | get(test_par130) -> {ok, test_val}; 169 | get(test_par13) -> {ok, test_val}; 170 | get(test_par129) -> {ok, test_val}; 171 | get(test_par128) -> {ok, test_val}; 172 | get(test_par127) -> {ok, test_val}; 173 | get(test_par126) -> {ok, test_val}; 174 | get(test_par125) -> {ok, test_val}; 175 | get(test_par124) -> {ok, test_val}; 176 | get(test_par123) -> {ok, test_val}; 177 | get(test_par122) -> {ok, test_val}; 178 | get(test_par121) -> {ok, test_val}; 179 | get(test_par120) -> {ok, test_val}; 180 | get(test_par12) -> {ok, test_val}; 181 | get(test_par119) -> {ok, test_val}; 182 | get(test_par118) -> {ok, test_val}; 183 | get(test_par117) -> {ok, test_val}; 184 | get(test_par116) -> {ok, test_val}; 185 | get(test_par115) -> {ok, test_val}; 186 | get(test_par114) -> {ok, test_val}; 187 | get(test_par113) -> {ok, test_val}; 188 | get(test_par112) -> {ok, test_val}; 189 | get(test_par111) -> {ok, test_val}; 190 | get(test_par110) -> {ok, test_val}; 191 | get(test_par11) -> {ok, test_val}; 192 | get(test_par109) -> {ok, test_val}; 193 | get(test_par108) -> {ok, test_val}; 194 | get(test_par107) -> {ok, test_val}; 195 | get(test_par106) -> {ok, test_val}; 196 | get(test_par105) -> {ok, test_val}; 197 | get(test_par104) -> {ok, test_val}; 198 | get(test_par103) -> {ok, test_val}; 199 | get(test_par102) -> {ok, test_val}; 200 | get(test_par101) -> {ok, test_val}; 201 | get(test_par100) -> {ok, test_val}; 202 | get(test_par10) -> {ok, test_val}; 203 | get(test_par1) -> {ok, test_val}; 204 | get(_) -> undefined. 205 | 206 | -------------------------------------------------------------------------------- /benchmark/eenv_benchmark.erl: -------------------------------------------------------------------------------- 1 | -module(eenv_benchmark). 2 | 3 | -export([test/1]). 4 | -export([test/2]). 5 | -export([test_code/0]). 6 | 7 | -include("eenv_benchmark.hrl"). 8 | 9 | -define(INCR, 20). 10 | -define(CAPACITY, 200). 11 | 12 | 13 | -define(PAR, test_par). 14 | -define(PAR_1, test_par1). 15 | -define(PAR_20, test_par20). 16 | -define(PAR_40, test_par40). 17 | -define(PAR_60, test_par60). 18 | -define(PAR_80, test_par80). 19 | -define(PAR_100, test_par100). 20 | -define(PAR_120, test_par120). 21 | -define(PAR_140, test_par140). 22 | -define(PAR_160, test_par160). 23 | -define(PAR_180, test_par180). 24 | -define(PAR_5, test_par1). 25 | -define(PAR_25, test_par20). 26 | -define(PAR_45, test_par40). 27 | -define(PAR_65, test_par60). 28 | -define(PAR_85, test_par80). 29 | -define(PAR_105, test_par100). 30 | -define(PAR_125, test_par120). 31 | -define(PAR_145, test_par140). 32 | -define(PAR_165, test_par160). 33 | -define(PAR_185, test_par180). 34 | -define(VAL, {ok, test_val}). 35 | 36 | test(Count) -> 37 | test(1, Count), 38 | test(10, Count), 39 | test(20, Count), 40 | test(30, Count), 41 | test(40, Count), 42 | test(50, Count), 43 | test(1000, Count), 44 | test(2000, Count), 45 | test(3000, Count), 46 | test(5000, Count), 47 | test(10000, Count), 48 | test(15000, Count), 49 | test(20000, Count), 50 | ok. 51 | 52 | %% @doc ProcNum: Process number running task at the same time. 53 | %% Count : Each process running function times. 54 | -spec test(ProcNum, Count) -> 'ok' when 55 | ProcNum :: integer(), 56 | Count :: integer(). 57 | test(ProcNum, Count) -> 58 | setup(), 59 | 60 | LoopFunc = fun() -> run_loop(Count) end, 61 | {LoopTime, _LoopCount} = benchmark(ProcNum, LoopFunc), 62 | timer:sleep(400), 63 | EenvFunc = fun() -> run_eenv(Count) end, 64 | {EenvTime, EenvCount} = benchmark(ProcNum, EenvFunc), 65 | timer:sleep(400), 66 | CodeFunc = fun() -> run_code(Count) end, 67 | {CodeTime, CodeCount} = benchmark(ProcNum, CodeFunc), 68 | timer:sleep(400), 69 | AppFunc = fun() -> run_application(Count) end, 70 | {AppTime, AppCount} = benchmark(ProcNum, AppFunc), 71 | timer:sleep(400), 72 | DictFunc = fun() -> init_dict(), run_dict(Count) end, 73 | {DictTime, DictCount} = benchmark(ProcNum, DictFunc), 74 | timer:sleep(400), 75 | RecFunc = fun() -> run_record(Count, #rec{}) end, 76 | {RecTime, RecCount} = benchmark(ProcNum, RecFunc), 77 | timer:sleep(400), 78 | MapFunc = fun() -> run_map(Count, init_map()) end, 79 | {MapTime, MapCount} = benchmark(ProcNum, MapFunc), 80 | 81 | Times = [ 82 | {eenv, EenvTime - LoopTime, EenvCount}, 83 | {code, CodeTime - LoopTime, CodeCount}, 84 | {app, AppTime - LoopTime, AppCount}, 85 | {dict, DictTime - LoopTime, DictCount}, 86 | {rec, RecTime - LoopTime, RecCount}, 87 | {map, MapTime - LoopTime, MapCount}], 88 | printf(ProcNum, Count, LoopTime, Times), 89 | cleanup(). 90 | 91 | init_dict() -> 92 | [begin 93 | Par = list_to_atom(atom_to_list(?PAR) ++ integer_to_list(Seq)), 94 | erlang:put(Par, ?VAL) 95 | end || Seq <- lists:seq(1, ?CAPACITY)]. 96 | 97 | init_map() -> 98 | lists:foldl(fun(Seq, Acc) -> 99 | Par = list_to_atom(atom_to_list(?PAR) ++ integer_to_list(Seq)), 100 | maps:put(Par, ?VAL, Acc) 101 | end, maps:new(), lists:seq(1, ?CAPACITY)). 102 | 103 | setup() -> 104 | application:load(ssl), 105 | ok = eenv:load(ssl), 106 | List = [begin {list_to_atom(atom_to_list(?PAR) ++ integer_to_list(S)), test_val} 107 | end || S <- lists:seq(1, ?CAPACITY)], 108 | ok = eenv:set(ssl, List). 109 | 110 | printf(ProcNum, Count, LoopTime, Times) -> 111 | [{MinType, MinTime, MinCount}|_] = ListTime = lists:keysort(2, Times), 112 | io:format("Run ProcNum=~p processes Count=~p count/process. EmptyLoop: ~6.3fns/loop~n", 113 | [ProcNum, Count - MinCount, LoopTime/((Count - MinCount)*ProcNum/?INCR)]), 114 | io:format("~s~n", [lists:duplicate(104, $-)]), 115 | io:format("~4s|~25s|~22s|~22s|~26s|~n", ['Type', 'Time/(ProcNum*Count) ns', 116 | 'Time/ProcNum us', 'Time/MinTime', 'Time/PrevMinTime']), 117 | 118 | lists:foldl(fun({Type, Time, ExCount}, {LastType, LastTime}) -> 119 | RunCount = Count - ExCount, 120 | case MinTime == 0 orelse LastTime == 0 of 121 | true -> 122 | io:format("~4s|~25.3f|~22.3f|~15.2p ~4s |~15.2p ~4s=~4s |~n", 123 | [Type, Time/(RunCount*ProcNum), Time/(ProcNum*1000), Time, MinType, Time, Type, LastType]); 124 | false when Type =:= app orelse Type =:= rec orelse Type =:= map -> 125 | io:format("~4s|~25.3f|~22.3f|~15.2fx ~4s |~11.2f x ~4s = ~3s |~n", 126 | [Type, Time/(RunCount*ProcNum), Time/(ProcNum*1000), Time/MinTime, MinType, Time/LastTime, LastType, Type]); 127 | false -> 128 | io:format("~4s|~25.3f|~22.3f|~15.2fx ~4s |~11.2f x ~4s = ~4s |~n", 129 | [Type, Time/(RunCount*ProcNum), Time/(ProcNum*1000), Time/MinTime, MinType, Time/LastTime, LastType, Type]) 130 | end, 131 | {Type, Time} 132 | end, 133 | {MinType, MinTime}, ListTime), 134 | io:format("~s~n", [lists:duplicate(104, $-)]). 135 | 136 | cleanup() -> 137 | ok = eenv:unload(ssl), 138 | application:unload(ssl), 139 | ok. 140 | 141 | benchmark(ProcNum, Func) -> 142 | erlang:garbage_collect(), 143 | Pids = [begin spawn(fun() -> worker(Func) end) end|| _<- lists:seq(1, ProcNum)], 144 | StartMsg = {start, self()}, 145 | collect(Pids, StartMsg, ProcNum). 146 | 147 | worker(Func) -> 148 | receive {start, Pid} -> 149 | Start = erlang:monotonic_time(), 150 | ExCount = Func(), 151 | End = erlang:monotonic_time(), 152 | Time = erlang:convert_time_unit(End - Start, native, nano_seconds), 153 | erlang:send(Pid, {Time, ExCount}) 154 | end. 155 | 156 | collect([], _Msg, ProcNum) -> finish(ProcNum, 0, 0); 157 | collect([Pid|Pids], Msg, ProcNum) -> 158 | erlang:send(Pid, Msg), 159 | collect(Pids, Msg, ProcNum). 160 | 161 | finish(0, TimeAcc, CountAcc) -> {TimeAcc, CountAcc}; 162 | finish(ProcNum, TimeAcc, CountAcc) -> 163 | receive {Time, Count} -> 164 | finish(ProcNum - 1, Time + TimeAcc, CountAcc + Count) 165 | end. 166 | 167 | run_loop(Count)when Count =< 0 -> Count; 168 | run_loop(Count) -> 169 | run_loop(Count - ?INCR). 170 | 171 | run_eenv(Count)when Count =< 0 -> Count; 172 | run_eenv(Count) -> 173 | ?VAL = eenv:get(ssl, ?PAR_1), 174 | ?VAL = eenv:get(ssl, ?PAR_20), 175 | ?VAL = eenv:get(ssl, ?PAR_40), 176 | ?VAL = eenv:get(ssl, ?PAR_60), 177 | ?VAL = eenv:get(ssl, ?PAR_80), 178 | ?VAL = eenv:get(ssl, ?PAR_100), 179 | ?VAL = eenv:get(ssl, ?PAR_120), 180 | ?VAL = eenv:get(ssl, ?PAR_140), 181 | ?VAL = eenv:get(ssl, ?PAR_160), 182 | ?VAL = eenv:get(ssl, ?PAR_180), 183 | ?VAL = eenv:get(ssl, ?PAR_5), 184 | ?VAL = eenv:get(ssl, ?PAR_25), 185 | ?VAL = eenv:get(ssl, ?PAR_45), 186 | ?VAL = eenv:get(ssl, ?PAR_65), 187 | ?VAL = eenv:get(ssl, ?PAR_85), 188 | ?VAL = eenv:get(ssl, ?PAR_105), 189 | ?VAL = eenv:get(ssl, ?PAR_125), 190 | ?VAL = eenv:get(ssl, ?PAR_145), 191 | ?VAL = eenv:get(ssl, ?PAR_165), 192 | ?VAL = eenv:get(ssl, ?PAR_185), 193 | run_eenv(Count - ?INCR). 194 | 195 | run_application(Count)when Count =< 0 -> Count; 196 | run_application(Count) -> 197 | ?VAL = application:get_env(ssl, ?PAR_1), 198 | ?VAL = application:get_env(ssl, ?PAR_20), 199 | ?VAL = application:get_env(ssl, ?PAR_40), 200 | ?VAL = application:get_env(ssl, ?PAR_60), 201 | ?VAL = application:get_env(ssl, ?PAR_80), 202 | ?VAL = application:get_env(ssl, ?PAR_100), 203 | ?VAL = application:get_env(ssl, ?PAR_120), 204 | ?VAL = application:get_env(ssl, ?PAR_140), 205 | ?VAL = application:get_env(ssl, ?PAR_160), 206 | ?VAL = application:get_env(ssl, ?PAR_180), 207 | ?VAL = application:get_env(ssl, ?PAR_5), 208 | ?VAL = application:get_env(ssl, ?PAR_25), 209 | ?VAL = application:get_env(ssl, ?PAR_45), 210 | ?VAL = application:get_env(ssl, ?PAR_65), 211 | ?VAL = application:get_env(ssl, ?PAR_85), 212 | ?VAL = application:get_env(ssl, ?PAR_105), 213 | ?VAL = application:get_env(ssl, ?PAR_125), 214 | ?VAL = application:get_env(ssl, ?PAR_145), 215 | ?VAL = application:get_env(ssl, ?PAR_165), 216 | ?VAL = application:get_env(ssl, ?PAR_185), 217 | run_application(Count - ?INCR). 218 | 219 | run_dict(Count)when Count =< 0 -> Count; 220 | run_dict(Count) -> 221 | ?VAL = erlang:get(?PAR_1), 222 | ?VAL = erlang:get(?PAR_20), 223 | ?VAL = erlang:get(?PAR_40), 224 | ?VAL = erlang:get(?PAR_60), 225 | ?VAL = erlang:get(?PAR_80), 226 | ?VAL = erlang:get(?PAR_100), 227 | ?VAL = erlang:get(?PAR_120), 228 | ?VAL = erlang:get(?PAR_140), 229 | ?VAL = erlang:get(?PAR_160), 230 | ?VAL = erlang:get(?PAR_180), 231 | ?VAL = erlang:get(?PAR_5), 232 | ?VAL = erlang:get(?PAR_25), 233 | ?VAL = erlang:get(?PAR_45), 234 | ?VAL = erlang:get(?PAR_65), 235 | ?VAL = erlang:get(?PAR_85), 236 | ?VAL = erlang:get(?PAR_105), 237 | ?VAL = erlang:get(?PAR_125), 238 | ?VAL = erlang:get(?PAR_145), 239 | ?VAL = erlang:get(?PAR_165), 240 | ?VAL = erlang:get(?PAR_185), 241 | run_dict(Count - ?INCR). 242 | 243 | run_code(Count)when Count =< 0 -> Count; 244 | run_code(Count) -> 245 | ?VAL = eenv_mock:get(ssl, ?PAR_1), 246 | ?VAL = eenv_mock:get(ssl, ?PAR_20), 247 | ?VAL = eenv_mock:get(ssl, ?PAR_40), 248 | ?VAL = eenv_mock:get(ssl, ?PAR_60), 249 | ?VAL = eenv_mock:get(ssl, ?PAR_80), 250 | ?VAL = eenv_mock:get(ssl, ?PAR_100), 251 | ?VAL = eenv_mock:get(ssl, ?PAR_120), 252 | ?VAL = eenv_mock:get(ssl, ?PAR_140), 253 | ?VAL = eenv_mock:get(ssl, ?PAR_160), 254 | ?VAL = eenv_mock:get(ssl, ?PAR_180), 255 | ?VAL = eenv_mock:get(ssl, ?PAR_5), 256 | ?VAL = eenv_mock:get(ssl, ?PAR_25), 257 | ?VAL = eenv_mock:get(ssl, ?PAR_45), 258 | ?VAL = eenv_mock:get(ssl, ?PAR_65), 259 | ?VAL = eenv_mock:get(ssl, ?PAR_85), 260 | ?VAL = eenv_mock:get(ssl, ?PAR_105), 261 | ?VAL = eenv_mock:get(ssl, ?PAR_125), 262 | ?VAL = eenv_mock:get(ssl, ?PAR_145), 263 | ?VAL = eenv_mock:get(ssl, ?PAR_165), 264 | ?VAL = eenv_mock:get(ssl, ?PAR_185), 265 | run_code(Count - ?INCR). 266 | 267 | 268 | run_record(Count, _Rec)when Count =< 0 -> Count; 269 | run_record(Count, Rec) -> 270 | #rec{?PAR_1 = {ok, test_val}} = Rec, 271 | #rec{?PAR_20 = {ok, test_val}} = Rec, 272 | #rec{?PAR_40 = {ok, test_val}} = Rec, 273 | #rec{?PAR_60 = {ok, test_val}} = Rec, 274 | #rec{?PAR_80 = {ok, test_val}} = Rec, 275 | #rec{?PAR_100 = {ok, test_val}} = Rec, 276 | #rec{?PAR_120 = {ok, test_val}} = Rec, 277 | #rec{?PAR_140 = {ok, test_val}} = Rec, 278 | #rec{?PAR_160 = {ok, test_val}} = Rec, 279 | #rec{?PAR_180 = {ok, test_val}} = Rec, 280 | #rec{?PAR_5 = {ok, test_val}} = Rec, 281 | #rec{?PAR_25 = {ok, test_val}} = Rec, 282 | #rec{?PAR_45 = {ok, test_val}} = Rec, 283 | #rec{?PAR_65 = {ok, test_val}} = Rec, 284 | #rec{?PAR_85 = {ok, test_val}} = Rec, 285 | #rec{?PAR_105 = {ok, test_val}} = Rec, 286 | #rec{?PAR_125 = {ok, test_val}} = Rec, 287 | #rec{?PAR_145 = {ok, test_val}} = Rec, 288 | #rec{?PAR_165 = {ok, test_val}} = Rec, 289 | #rec{?PAR_185 = {ok, test_val}} = Rec, 290 | run_record(Count - ?INCR, Rec). 291 | 292 | run_map(Count, _Map)when Count =< 0 -> Count; 293 | run_map(Count, Map) -> 294 | #{?PAR_1 := {ok, test_val}} = Map, 295 | #{?PAR_20 := {ok, test_val}} = Map, 296 | #{?PAR_40 := {ok, test_val}} = Map, 297 | #{?PAR_60 := {ok, test_val}} = Map, 298 | #{?PAR_80 := {ok, test_val}} = Map, 299 | #{?PAR_100 := {ok, test_val}} = Map, 300 | #{?PAR_120 := {ok, test_val}} = Map, 301 | #{?PAR_140 := {ok, test_val}} = Map, 302 | #{?PAR_160 := {ok, test_val}} = Map, 303 | #{?PAR_180 := {ok, test_val}} = Map, 304 | #{?PAR_5 := {ok, test_val}} = Map, 305 | #{?PAR_25 := {ok, test_val}} = Map, 306 | #{?PAR_45 := {ok, test_val}} = Map, 307 | #{?PAR_65 := {ok, test_val}} = Map, 308 | #{?PAR_85 := {ok, test_val}} = Map, 309 | #{?PAR_105 := {ok, test_val}} = Map, 310 | #{?PAR_125 := {ok, test_val}} = Map, 311 | #{?PAR_145 := {ok, test_val}} = Map, 312 | #{?PAR_165 := {ok, test_val}} = Map, 313 | #{?PAR_185 := {ok, test_val}} = Map, 314 | run_map(Count - ?INCR, Map). 315 | 316 | test_code() -> 317 | Count = 10000, 318 | MinProcNum = 100, 319 | MaxProcNum = 1000, 320 | io:format("~s~n", [lists:duplicate(30, $-)]), 321 | io:format("|Process|Time/(Count*ProcNum)|~n"), 322 | Func = fun() -> run_code(Count) end, 323 | lists:foreach(fun(ProcNum) -> 324 | Time = benchmark(ProcNum, Func), 325 | io:format("|~6w | ~17.4fns| ~n", [ProcNum, Time/(Count*ProcNum)]) 326 | end, lists:seq(MinProcNum, MaxProcNum, 100)), 327 | io:format("~s~n", [lists:duplicate(30, $-)]), 328 | ok. 329 | -------------------------------------------------------------------------------- /src/eenv.erl: -------------------------------------------------------------------------------- 1 | -module(eenv). 2 | %% API 3 | -export([load/1, unload/1]). 4 | -export([get/2, get/3]). 5 | -export([set/2, set/3, set/4]). 6 | -export([unset/2, unset/3]). 7 | 8 | -compile([{inline, [ 9 | {load, 1}, {unload, 1}, 10 | {set, 2}, {set, 3}, {unset, 2}, 11 | {get, 2}, {get, 3}]}]). 12 | 13 | -define(ROUTER_MOD, eenv_router). 14 | -define(GET, get). 15 | -define(SET, set). 16 | -define(GET_LOADED_APPS, get_loaded_apps). 17 | -define(NONE, none). 18 | -define(UNDEFINED, undefined). 19 | -define(UNLOADED, unloaded). 20 | -define(COMPILE_OPT, [verbose, report_errors, report_warnings]). 21 | 22 | %% -module(Module). 23 | -define(make_module(MOD_), erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(MOD_)])). 24 | %% -export([Function/N]). 25 | -define(make_export(FUNC_, N_), erl_syntax:attribute( 26 | erl_syntax:atom(export), 27 | [erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(FUNC_), erl_syntax:integer(N_))])] 28 | )). 29 | -define(make_app_mod(APP_), list_to_atom("eenv_" ++ atom_to_list(APP_))). 30 | 31 | %%==================================================================== 32 | %% API functions 33 | %%==================================================================== 34 | %% @doc Loads the application configuration for an application into the beam. 35 | -spec load(Applications) -> 'ok' when 36 | Applications :: atom() | [atom()]. 37 | load(App) when is_atom(App) -> 38 | load([App]); 39 | load(Apps) when is_list(Apps) -> 40 | load_app_module(Apps), 41 | update_router_module(load, Apps). 42 | 43 | %% @doc Deletes the application configuration beam file. 44 | unload(App) when is_atom(App) -> 45 | unload([App]); 46 | unload(Apps) when is_list(Apps) -> 47 | update_router_module(unload, Apps), 48 | unload_app_module(Apps). 49 | 50 | %% @doc Returns the value of configuration parameter Par for Application. 51 | %% Returns undefined if the configuration parameter does not exist: 52 | %% Returns unloaded if application is not loaded by eenv. 53 | %% 54 | -spec get(Application, Par) -> 'undefined' | 'unloaded' | {'ok', Val} when 55 | Application :: atom(), 56 | Par :: atom(), 57 | Val :: term(). 58 | get(Application, Par) -> 59 | ?ROUTER_MOD:get(Application, Par). 60 | 61 | %% @doc Works like {@link get/2} but 62 | %% Returns value Default when configuration parameter Par does not exist. 63 | %% Returns application:get_env(App, Par, Default) when application is not loaded by eenv. 64 | -spec get(Application, Par, Default) -> Val when 65 | Application :: atom(), 66 | Par :: atom(), 67 | Default :: term(), 68 | Val :: term(). 69 | get(Application, Par, Default) -> 70 | case ?ROUTER_MOD:get(Application, Par) of 71 | {ok, Value} -> Value; 72 | ?UNDEFINED -> Default; 73 | ?UNLOADED -> application:get_env(Application, Par, Default) 74 | end. 75 | 76 | %% @doc Sets the value of configuration parameter Par for Application. Same as application:get_env/3. 77 | %% Use this function only if you know what you are doing, that is, on your own applications. 78 | %% It is very application-dependent and configuration parameter-dependent when and how often the value is read by the application. 79 | %% Careless use of this function can put the application in a weird, inconsistent, and malfunctioning state. 80 | -spec set(Application, Par, Val) -> 'ok' when 81 | Application :: atom(), 82 | Par :: atom(), 83 | Val :: term(). 84 | set(Application, Par, Val) -> 85 | ok = application:set_env(Application, Par, Val), 86 | load_app_module(Application), 87 | ok. 88 | 89 | %% @doc Sets the value of configuration parameter Par for Application. Same as application:set_env/4. 90 | -spec set(Application, Par, Val, Opt) -> 'ok' when 91 | Application :: atom(), 92 | Par :: atom(), 93 | Opt :: [{timeout, timeout()} | {persistent, boolean()}], 94 | Val :: term(). 95 | set(Application, Par, Val, Opt) -> 96 | ok = application:set_env(Application, Par, Val, Opt), 97 | load_app_module(Application), 98 | ok. 99 | 100 | %% @doc Works like {@link set/3}. with setting in batches. 101 | -spec set(Application, List) -> 'ok' when 102 | Application :: atom(), 103 | List :: [{atom(), term()}]. 104 | set(Application, List) -> 105 | [begin ok = application:set_env(Application, Par, Value) end || {Par, Value} <- List], 106 | load_app_module(Application), 107 | ok. 108 | 109 | %% @doc Removes the configuration parameter Par and its value for Application. 110 | %% Same as application:unset_env(Application, Par). 111 | -spec unset(Application, Pars) -> 'ok' when 112 | Application :: atom(), 113 | Pars :: atom() | [atom()]. 114 | unset(Application, Par) when is_atom(Par) -> 115 | ok = application:unset_env(Application, Par), 116 | load_app_module(Application), 117 | ok; 118 | unset(Application, Pars) when is_list(Pars) -> 119 | [begin ok = application:unset_env(Application, Par) end || Par <- Pars], 120 | load_app_module(Application), 121 | ok. 122 | 123 | %% @doc Removes the configuration parameter Par and its value for Application. 124 | %% Same as application:unset_env(Application, Par, Opt). 125 | -spec unset(Application, Pars, Opt) -> 'ok' when 126 | Application :: atom(), 127 | Opt :: [{timeout, timeout()} | {persistent, boolean()}], 128 | Pars :: atom() | [atom()]. 129 | unset(Application, Par, Opt) when is_atom(Par) -> 130 | ok = application:unset_env(Application, Par, Opt), 131 | load_app_module(Application), 132 | ok; 133 | unset(Application, Pars, Opt) when is_list(Pars) -> 134 | [begin ok = application:unset_env(Application, Par, Opt) end || Par <- Pars], 135 | load_app_module(Application), 136 | ok. 137 | 138 | %%==================================================================== 139 | %% Internal functions 140 | %%==================================================================== 141 | update_router_module(Type, UpdateApps) -> 142 | Apps = get_loaded_apps(), 143 | LoadApps = case Type of load -> Apps ++ UpdateApps; unload -> Apps -- UpdateApps end, 144 | SortApps = lists:usort(LoadApps), 145 | Forms = router_forms(SortApps), 146 | {ok, ?ROUTER_MOD, Bin} = compile:forms(Forms, ?COMPILE_OPT), 147 | code:purge(?ROUTER_MOD), 148 | {module, ?ROUTER_MOD} = code:load_binary(?ROUTER_MOD, "eenv_router.beam", Bin), 149 | ok. 150 | 151 | get_loaded_apps() -> 152 | case erlang:function_exported(?ROUTER_MOD, ?GET_LOADED_APPS, 0) of 153 | true -> ?ROUTER_MOD:?GET_LOADED_APPS(); 154 | false -> [] 155 | end. 156 | 157 | %% eenv_router.beam 158 | %%-module(eenv_router). 159 | %%-export([get/2]). 160 | %% get('load_app1', Par) -> eenv_'load_app1':get(Par); 161 | %% get('load_app2', Par) -> eenv_'load_app2':get(Par); 162 | %% get(_, _) -> unloaded. 163 | router_forms(LoadApps) -> 164 | [begin erl_syntax:revert(X) end || X <- [ 165 | ?make_module(?ROUTER_MOD), 166 | ?make_export(?GET, 2), 167 | ?make_export(?GET_LOADED_APPS, 0), 168 | make_router_func(LoadApps), 169 | make_loaded_apps_func(LoadApps) 170 | ]]. 171 | 172 | make_router_func(LoadApps) -> 173 | DefaultClause = [ 174 | erl_syntax:clause( 175 | [erl_syntax:variable("_"), erl_syntax:variable("_")], 176 | ?NONE, 177 | [erl_syntax:atom(?UNLOADED)] 178 | ) 179 | ], 180 | Clause = make_router_clause(LoadApps, DefaultClause), 181 | erl_syntax:function(erl_syntax:atom(?GET), Clause). 182 | 183 | make_loaded_apps_func(LoadApps) -> 184 | Clause = 185 | [erl_syntax:clause([], none, 186 | [erl_syntax:abstract(LoadApps)])], 187 | erl_syntax:function(erl_syntax:atom(?GET_LOADED_APPS), Clause). 188 | 189 | make_router_clause([], Acc) -> Acc; 190 | make_router_clause([LoadApp | TailApps], Acc) -> 191 | Clause = 192 | erl_syntax:clause( 193 | [erl_syntax:abstract(LoadApp), erl_syntax:variable("Par")], 194 | ?NONE, 195 | [erl_syntax:application(erl_syntax:atom(?make_app_mod(LoadApp)), 196 | erl_syntax:atom(?GET), 197 | [erl_syntax:variable("Par")])] 198 | ), 199 | make_router_clause(TailApps, [Clause | Acc]). 200 | 201 | %%eenv_'$load_app'.beam 202 | %%-module(eenv_'$load_app'). 203 | %%-export([get/1]). 204 | %% get('par_1') -> {ok, term_val_1}; 205 | %% get('par_2') -> {ok, term_val_2}; 206 | %% get(_) -> undefined. 207 | load_app_module([]) -> ok; 208 | load_app_module([LoadApp | LoadApps]) -> 209 | load_app_module(LoadApp), 210 | load_app_module(LoadApps); 211 | load_app_module(App) when is_atom(App) -> 212 | AppMod = ?make_app_mod(App), 213 | Kvs = application:get_all_env(App), 214 | SortKvs = lists:keysort(1, Kvs), 215 | Forms = app_forms(AppMod, SortKvs), 216 | {ok, AppMod, Bin} = compile:forms(Forms, ?COMPILE_OPT), 217 | code:purge(AppMod), 218 | BeamFile = atom_to_list(AppMod) ++ ".beam", 219 | {module, AppMod} = code:load_binary(AppMod, BeamFile, Bin), 220 | ok. 221 | 222 | app_forms(AppName, Kvs) -> 223 | [begin erl_syntax:revert(X) end || X 224 | <- [ 225 | ?make_module(AppName), 226 | ?make_export(?GET, 1), 227 | make_app_func(Kvs) 228 | ] 229 | ]. 230 | 231 | make_app_func(Kvs) -> 232 | DefaultClause = [ 233 | erl_syntax:clause( 234 | [erl_syntax:variable("_")], 235 | ?NONE, 236 | [erl_syntax:atom(?UNDEFINED)] 237 | ) 238 | ], 239 | Clause = make_app_clause(Kvs, DefaultClause), 240 | erl_syntax:function(erl_syntax:atom(?GET), Clause). 241 | 242 | make_app_clause([], Acc) -> Acc; 243 | make_app_clause([{Par, Val} | Kvs], Acc) -> 244 | Clause = 245 | erl_syntax:clause([erl_syntax:abstract(Par)], 246 | ?NONE, 247 | [erl_syntax:abstract({ok, Val})]), 248 | make_app_clause(Kvs, [Clause | Acc]). 249 | 250 | %% delete eenv_'$load_app'.beam 251 | unload_app_module([]) -> ok; 252 | unload_app_module([App | UnloadApps]) -> 253 | unload_app_module(App), 254 | unload_app_module(UnloadApps); 255 | unload_app_module(UnloadApp) -> 256 | UnloadAppMod = ?make_app_mod(UnloadApp), 257 | code:purge(UnloadAppMod), 258 | code:delete(UnloadAppMod). 259 | 260 | -ifdef(TEST). 261 | -include_lib("eunit/include/eunit.hrl"). 262 | 263 | get_test() -> 264 | App = crypto, 265 | Par = test1_par, 266 | Val = test1_val, 267 | DefaultVal = test1_default_val, 268 | ok = eenv:load(crypto), 269 | ?assertEqual(ok, eenv:set(App, Par, Val)), 270 | ?assertEqual({ok, Val}, eenv:get(App, Par)), 271 | ?assertEqual(Val, eenv:get(App, Par, DefaultVal)), 272 | ?assertEqual(undefined, eenv:get(App, no_exist_par)), 273 | ?assertEqual(DefaultVal, eenv:get(App, no_exist_par, DefaultVal)), 274 | ?assertEqual(DefaultVal, eenv:get(no_exist_app, Par, DefaultVal)), 275 | ok = eenv:unload(App), 276 | ok. 277 | 278 | set_test() -> 279 | App = crypto, 280 | Par = test2_par, 281 | Val = test2_val, 282 | Par1 = test2_par1, 283 | Val1 = test2_val1, 284 | ok = eenv:load(crypto), 285 | ?assertEqual(ok, eenv:set(App, Par, Val)), 286 | ?assertEqual(ok, eenv:set(App, Par, Val, [{timeout, 5000}])), 287 | ?assertEqual({ok, Val}, eenv:get(App, Par)), 288 | ?assertEqual(ok, eenv:set(App, [{Par1, Val1}, {Par, Val}])), 289 | ?assertEqual({ok, Val1}, eenv:get(App, Par1)), 290 | ?assertEqual({ok, Val}, eenv:get(App, Par)), 291 | ok = eenv:unload(App). 292 | 293 | unset_test() -> 294 | App = crypto, 295 | Par = test3_par, 296 | Val = test3_val, 297 | Par1 = test3_par1, 298 | Val1 = test3_val1, 299 | ok = eenv:load(crypto), 300 | ?assertEqual(ok, eenv:set(crypto, Par, Val)), 301 | ?assertEqual({ok, Val}, eenv:get(crypto, Par)), 302 | ?assertEqual(ok, eenv:unset(App, Par)), 303 | ?assertEqual(ok, eenv:unset(App, Par1, [{timeout, 5000}])), 304 | ?assertEqual(undefined, eenv:get(crypto, Par)), 305 | ?assertEqual(undefined, eenv:get(crypto, Par1)), 306 | ?assertEqual(ok, eenv:set(crypto, [{Par, Val}, {Par1, Val1}])), 307 | ?assertEqual({ok, Val}, eenv:get(crypto, Par)), 308 | ?assertEqual({ok, Val1}, eenv:get(crypto, Par1)), 309 | ?assertEqual(ok, eenv:unset(App, [Par, Par1], [{timeout, 5000}])), 310 | ?assertEqual(undefined, eenv:get(crypto, Par)), 311 | ?assertEqual(undefined, eenv:get(crypto, Par1)), 312 | ok = eenv:unload(App), 313 | ok. 314 | 315 | load_test() -> 316 | App = crypto, 317 | AppBeam = list_to_atom("eenv_" ++ atom_to_list(App)), 318 | ?assertException(error, undef, AppBeam:module_info(exports)), 319 | ok = eenv:load(App), 320 | ?assertEqual([{get, 1}, {module_info, 0}, {module_info, 1}], lists:usort(AppBeam:module_info(exports))), 321 | ?assertEqual({ok, []}, eenv:get(App, included_applications)), 322 | ?assertEqual(undefined, eenv:get(App, no_exist)), 323 | ?assertEqual(?UNLOADED, eenv:get(no_load_app, no_exist)), 324 | ok = eenv:unload(App), 325 | ?assertException(error, undef, AppBeam:module_info(exports)), 326 | ?assertEqual(?UNLOADED, eenv:get(App, no_exist)), 327 | ok. 328 | 329 | -endif. 330 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | erl-env 2 | ===== 3 | [![Github Tag](https://img.shields.io/github/tag/zhongwencool/erl-env.svg)](https://github.com/zhongwencool/erl-env) 4 | [![Build Status](https://travis-ci.org/zhongwencool/erl-env.svg?branch=master)](https://travis-ci.org/zhongwencool/erl-env) 5 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/zhongwencool/erl-env) 6 | [![Hex.pm](https://img.shields.io/hexpm/v/eenv.svg)](http://hex.pm/packages/eenv) 7 | [![Hex.pm Downloads](https://img.shields.io/hexpm/dt/eenv.svg?style=flat-square)](https://hex.pm/packages/eenv) 8 | 9 | ## Goal 10 | `eenv` makes retrieving configuration parameters used by application faster and more stable then *application:get_env*. 11 | In a general way, the value of a configuration parameter is retrieved by calling *application:get_env* which caches params in the `ac_tab` ETS table, but the speed of reading ets table grows more and more slowly as concurrent volumes grows. 12 | `eenv` translates the ETS data into a dynamically constructed and loaded Erlang module. This can significantly reduce latency. 13 | PS: It is only for the situation which needs high reading concurrency and low writing needs. 14 | 15 | ## Rationale 16 | Application stores configuration in `ac_tab` ETS with `{{env, AppName, Key}, Value}`, 17 | `application:get_env/2-3` must lookup `ac_tab` by `{env, AppName, Key}` every time. 18 | 19 | 1. Configurations in `sys.config`. 20 | ```erlang 21 | [ 22 | {appname_1, [{ip, "127.0.0.1"}, {port, 8080}]}, 23 | {appname_2, [{log_level, debug}, {log_path, "log/debug.log"}]} 24 | ]. 25 | ``` 26 | 2. These configurations are present in the `ac_tab` table as the release starts. 27 | ```erlang 28 | [{{env, appname_1, ip}, "127.0.0.1"}, {{env, appname_1, port}, 8080}, 29 | {{env, appname_2, log_level}, debug}}, {{env, appname_2, log_path}, "log/debug.log"}]. 30 | ``` 31 | 3. `eenv` dynamic compiles configurations into beam by calling `eenv:load(AppName)`. 32 | It generates two beam files: 33 | ```erlang 34 | % eenv_router.beam 35 | -module(eenv_router). 36 | -export([get/2]). 37 | get(appname_1, Key) -> eenv_appname_1:get(Key); 38 | get(appname_2, Key) -> eenv_appname_2:get(Key); 39 | get(_, _) -> unload. 40 | 41 | % eenv_appname_1.beam 42 | -module(eenv_appname_1). 43 | -export([get/1]). 44 | get(ip) -> {ok, "127.0.0.1"}; 45 | get(port) -> {ok, 8080}; 46 | get(_) -> undefined. 47 | 48 | % eenv_appname_2.beam 49 | -module(eenv_appname_2). 50 | -export([get/1]). 51 | get(log_level) -> {ok, debug}; 52 | get(log_path) -> {ok, "log/debug.log"}; 53 | get(_) -> undefined. 54 | ``` 55 | we can retrieve parameters by `eenv:get/2-3.`, such as: 56 | ```erlang 57 | {ok, IP} = eenv:get(appname_1, ip), 58 | {ok, Port} = eenv:get(appname_1, port), 59 | LogLevel = eenv:get(appname_2, log_level, error), 60 | LogPath = eenv:get(appname_1, log_path, "log/error.log"). 61 | ``` 62 | Each loaded application will generate `eenv_'AppName'.beam` to save own configuration information. 63 | 64 | `eenv`'s code is very straightforward(lines < 200) and worth a visit. 65 | 66 | ## Quick Start 67 | 1. Load `eenv` when your application starts by `eenv:load(YourAppName)`. 68 | ```erlang 69 | % YourApp_app.erl 70 | -behaviour(application). 71 | % Application callbacks 72 | -export([start/2, stop/1]). 73 | start(_StartType, _StartArgs) -> 74 | eenv:load(your_app), 75 | your_app_sup:start_link(). 76 | 77 | stop(_State) -> 78 | eenv:unload(your_app), 79 | ok. 80 | ``` 81 | 2. Replace application's function with eenv's function. 82 | 83 | | Before | After | 84 | | :--------------------: | :-------------: | 85 | | _application:get/2-3_ | [eenv:get/2-3](https://github.com/zhongwencool/erl-env/blob/master/src/eenv.erl#L53) | 86 | | _application:set/2-4_ | [eenv:set/2-4](https://github.com/zhongwencool/erl-env/blob/master/src/eenv.erl#L79) | 87 | | _application:unset/2-3_ | [eenv:unset/2-3](https://github.com/zhongwencool/erl-env/blob/master/src/eenv.erl#L110) | 88 | 89 | ## Benchmark 90 | 91 | ### Benchmark Type Specification 92 | 93 | - `dict` copy params into process dictionary by `erlang:put/2`, fetch by `erlang:get/1`. 94 | - `rec` copy params into process state by record(`#state{key = Val}`) and fetch by `#state{key = Val} = State`. 95 | - `map` copy params into process state by map(`#{key = val}`)and fetch by `#{key => Val} = State`. 96 | - `app` fetch params by `application:get/2`. 97 | - `eenv` fetch params by `eenv:get/2`. 98 | - `code` fetch params by static beam. 99 | 100 | More detailed information see [eenv_benchmark.erl](https://github.com/zhongwencool/erl-env/blob/master/benchmark/eenv_benchmark.erl). 101 | ```shell 102 | zsh$ make benchmark 103 | ===> Verifying dependencies... 104 | ===> Compiling eenv 105 | Starting benchmark... 106 | Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] 107 | 108 | Eshell V9.0 (abort with ^G) 109 | 1> Run ProcNum=1 processes Count=10000 count/process. EmptyLoop: 8.000ns/loop 110 | -------------------------------------------------------------------------------------------------------- 111 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 112 | rec| 24.500| 245.000| 1.00x rec | 1.00 x rec = rec | 113 | dict| 50.800| 508.000| 2.07x rec | 2.07 x rec = dict | 114 | eenv| 73.600| 736.000| 3.00x rec | 1.45 x dict = eenv | 115 | map| 78.400| 784.000| 3.20x rec | 1.07 x eenv = map | 116 | code| 187.600| 1876.000| 7.66x rec | 2.39 x map = code | 117 | app| 449.200| 4492.000| 18.33x rec | 2.39 x code = app | 118 | -------------------------------------------------------------------------------------------------------- 119 | Run ProcNum=10 processes Count=10000 count/process. EmptyLoop: 6.200ns/loop 120 | -------------------------------------------------------------------------------------------------------- 121 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 122 | rec| 21.650| 216.500| 1.00x rec | 1.00 x rec = rec | 123 | dict| 40.780| 407.800| 1.88x rec | 1.88 x rec = dict | 124 | map| 65.500| 655.000| 3.03x rec | 1.61 x dict = map | 125 | code| 176.260| 1762.600| 8.14x rec | 2.69 x map = code | 126 | eenv| 198.180| 1981.800| 9.15x rec | 1.12 x code = eenv | 127 | app| 990.120| 9901.200| 45.73x rec | 5.00 x eenv = app | 128 | -------------------------------------------------------------------------------------------------------- 129 | Run ProcNum=20 processes Count=10000 count/process. EmptyLoop: 11.600ns/loop 130 | -------------------------------------------------------------------------------------------------------- 131 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 132 | rec| 21.600| 216.000| 1.00x rec | 1.00 x rec = rec | 133 | dict| 37.530| 375.300| 1.74x rec | 1.74 x rec = dict | 134 | map| 72.705| 727.050| 3.37x rec | 1.94 x dict = map | 135 | code| 243.830| 2438.300| 11.29x rec | 3.35 x map = code | 136 | eenv| 289.220| 2892.200| 13.39x rec | 1.19 x code = eenv | 137 | app| 1288.025| 12880.250| 59.63x rec | 4.45 x eenv = app | 138 | -------------------------------------------------------------------------------------------------------- 139 | Run ProcNum=30 processes Count=10000 count/process. EmptyLoop: 8.800ns/loop 140 | -------------------------------------------------------------------------------------------------------- 141 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 142 | rec| 27.173| 271.733| 1.00x rec | 1.00 x rec = rec | 143 | dict| 56.157| 561.567| 2.07x rec | 2.07 x rec = dict | 144 | map| 76.130| 761.300| 2.80x rec | 1.36 x dict = map | 145 | code| 274.173| 2741.733| 10.09x rec | 3.60 x map = code | 146 | eenv| 342.797| 3427.967| 12.62x rec | 1.25 x code = eenv | 147 | app| 1800.640| 18006.400| 66.26x rec | 5.25 x eenv = app | 148 | -------------------------------------------------------------------------------------------------------- 149 | Run ProcNum=40 processes Count=10000 count/process. EmptyLoop: 10.050ns/loop 150 | -------------------------------------------------------------------------------------------------------- 151 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 152 | rec| 28.973| 289.725| 1.00x rec | 1.00 x rec = rec | 153 | dict| 52.775| 527.750| 1.82x rec | 1.82 x rec = dict | 154 | map| 73.282| 732.825| 2.53x rec | 1.39 x dict = map | 155 | code| 336.410| 3364.100| 11.61x rec | 4.59 x map = code | 156 | eenv| 399.125| 3991.250| 13.78x rec | 1.19 x code = eenv | 157 | app| 2241.085| 22410.850| 77.35x rec | 5.61 x eenv = app | 158 | -------------------------------------------------------------------------------------------------------- 159 | Run ProcNum=50 processes Count=10000 count/process. EmptyLoop: 10.400ns/loop 160 | -------------------------------------------------------------------------------------------------------- 161 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 162 | rec| 30.304| 303.040| 1.00x rec | 1.00 x rec = rec | 163 | dict| 51.718| 517.180| 1.71x rec | 1.71 x rec = dict | 164 | map| 70.316| 703.160| 2.32x rec | 1.36 x dict = map | 165 | code| 384.044| 3840.440| 12.67x rec | 5.46 x map = code | 166 | eenv| 477.252| 4772.520| 15.75x rec | 1.24 x code = eenv | 167 | app| 2726.554| 27265.540| 89.97x rec | 5.71 x eenv = app | 168 | -------------------------------------------------------------------------------------------------------- 169 | Run ProcNum=1000 processes Count=10000 count/process. EmptyLoop: 10.956ns/loop 170 | -------------------------------------------------------------------------------------------------------- 171 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 172 | rec| 18.751| 187.506| 1.00x rec | 1.00 x rec = rec | 173 | dict| 38.307| 383.066| 2.04x rec | 2.04 x rec = dict | 174 | map| 60.377| 603.768| 3.22x rec | 1.58 x dict = map | 175 | code| 8852.114| 88521.138| 472.10x rec | 146.61 x map = code | 176 | eenv| 9247.929| 92479.286| 493.21x rec | 1.04 x code = eenv | 177 | app| 66608.656| 666086.560| 3552.35x rec | 7.20 x eenv = app | 178 | -------------------------------------------------------------------------------------------------------- 179 | Run ProcNum=2000 processes Count=10000 count/process. EmptyLoop: 10.706ns/loop 180 | -------------------------------------------------------------------------------------------------------- 181 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 182 | rec| 18.498| 184.981| 1.00x rec | 1.00 x rec = rec | 183 | dict| 37.629| 376.288| 2.03x rec | 2.03 x rec = dict | 184 | map| 59.790| 597.904| 3.23x rec | 1.59 x dict = map | 185 | code| 15319.678| 153196.775| 828.18x rec | 256.22 x map = code | 186 | eenv| 19704.738| 197047.378| 1065.23x rec | 1.29 x code = eenv | 187 | app| 165826.738| 1658267.384| 8964.53x rec | 8.42 x eenv = app | 188 | -------------------------------------------------------------------------------------------------------- 189 | Run ProcNum=3000 processes Count=10000 count/process. EmptyLoop: 12.050ns/loop 190 | -------------------------------------------------------------------------------------------------------- 191 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 192 | rec| 18.703| 187.035| 1.00x rec | 1.00 x rec = rec | 193 | dict| 40.587| 405.870| 2.17x rec | 2.17 x rec = dict | 194 | map| 59.714| 597.141| 3.19x rec | 1.47 x dict = map | 195 | code| 24968.905| 249689.051| 1334.99x rec | 418.14 x map = code | 196 | eenv| 35843.095| 358430.950| 1916.38x rec | 1.44 x code = eenv | 197 | app| 233007.906| 2330079.058| 12457.98x rec | 6.50 x eenv = app | 198 | -------------------------------------------------------------------------------------------------------- 199 | Run ProcNum=5000 processes Count=10000 count/process. EmptyLoop: 11.276ns/loop 200 | -------------------------------------------------------------------------------------------------------- 201 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 202 | rec| 18.808| 188.077| 1.00x rec | 1.00 x rec = rec | 203 | dict| 41.237| 412.371| 2.19x rec | 2.19 x rec = dict | 204 | map| 58.939| 589.391| 3.13x rec | 1.43 x dict = map | 205 | code| 46437.121| 464371.206| 2469.05x rec | 787.88 x map = code | 206 | eenv| 59476.405| 594764.053| 3162.35x rec | 1.28 x code = eenv | 207 | app| 473787.975| 4737879.751| 25191.22x rec | 7.97 x eenv = app | 208 | -------------------------------------------------------------------------------------------------------- 209 | Run ProcNum=10000 processes Count=10000 count/process. EmptyLoop: 10.829ns/loop 210 | -------------------------------------------------------------------------------------------------------- 211 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 212 | rec| 18.884| 188.843| 1.00x rec | 1.00 x rec = rec | 213 | dict| 39.479| 394.787| 2.09x rec | 2.09 x rec = dict | 214 | map| 60.383| 603.827| 3.20x rec | 1.53 x dict = map | 215 | code| 90985.045| 909850.445| 4818.04x rec | 1506.81 x map = code | 216 | eenv| 106457.887| 1064578.867| 5637.39x rec | 1.17 x code = eenv | 217 | app| 875741.508| 8757415.083| 46374.15x rec | 8.23 x eenv = app | 218 | -------------------------------------------------------------------------------------------------------- 219 | Run ProcNum=15000 processes Count=10000 count/process. EmptyLoop: 10.773ns/loop 220 | -------------------------------------------------------------------------------------------------------- 221 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 222 | rec| 19.000| 189.998| 1.00x rec | 1.00 x rec = rec | 223 | dict| 42.839| 428.392| 2.25x rec | 2.25 x rec = dict | 224 | map| 65.579| 655.790| 3.45x rec | 1.53 x dict = map | 225 | code| 110231.265| 1102312.651| 5801.70x rec | 1680.89 x map = code | 226 | eenv| 154514.285| 1545142.848| 8132.41x rec | 1.40 x code = eenv | 227 | app| 1103348.055| 11033480.554| 58071.52x rec | 7.14 x eenv = app | 228 | -------------------------------------------------------------------------------------------------------- 229 | Run ProcNum=20000 processes Count=10000 count/process. EmptyLoop: 10.800ns/loop 230 | -------------------------------------------------------------------------------------------------------- 231 | Type| Time/(ProcNum*Count) ns| Time/ProcNum us| Time/MinTime| Time/PrevMinTime| 232 | rec| 18.891| 188.906| 1.00x rec | 1.00 x rec = rec | 233 | dict| 39.378| 393.776| 2.08x rec | 2.08 x rec = dict | 234 | map| 61.373| 613.734| 3.25x rec | 1.56 x dict = map | 235 | code| 145870.193| 1458701.932| 7721.84x rec | 2376.77 x map = code | 236 | eenv| 206175.821| 2061758.207| 10914.20x rec | 1.41 x code = eenv | 237 | app| 1379935.745| 13799357.453| 73048.79x rec | 6.69 x eenv = app | 238 | -------------------------------------------------------------------------------------------------------- 239 | ``` 240 | 241 | ### Conclusion 242 | 243 | - `dict`, `rec`, `map` copy params into process memory is faster and consume less resources then `eenv`, `app`, `code`, 244 | but the problem is that it's very memory consuming(N copy data with N processes running) and difficult to update. 245 | `dict/rec ≈ 2.50`, `map/rec ≈ 3.10`, `map/dict ≈ 1.24`. 246 | **speed**: `record > map > dictionary` 247 | 248 | - `eenv` and `code`(static beam) almost the same, depend on the clause order and test sample. 249 | 250 | - `eenv` is about 7.2 times faster than `app` and `eenv` cost less CPU resources than `app`. 251 | 252 | - If CPU resources enough, `eenv` slower then `dict` about 6 times, and cost more CPU. 253 | 254 | ### Confused 255 | - Why eenv/code time is increase? it should be constant. 256 | 257 | It exhausts CPU resources when lots of processes running in busy circle, so time trend to increase. 258 | 259 | - But why dict/map/rec time almost constant? 260 | 261 | It only increase not obvious way. 262 | Because fetch data from memory cost very little CPU and super fast(0.0x us), it's hard to create lots of processes running at same time. 263 | You should see increase when run `make benchmark50000`. 264 | 265 | ## ChangeLog 266 | 267 | ## License 268 | See the [LICENSE](https://github.com/zhongwencool/erl-env/blob/master/LICENSE) file for license rights and limitations (MIT). 269 | 270 | --------------------------------------------------------------------------------