├── 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 | [](https://github.com/zhongwencool/erl-env)
4 | [](https://travis-ci.org/zhongwencool/erl-env)
5 | [](https://github.com/zhongwencool/erl-env)
6 | [](http://hex.pm/packages/eenv)
7 | [](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 |
--------------------------------------------------------------------------------