Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Optimising for the BEAM
Michał Muskała
May 31, 2018
Programming
2
520
Optimising for the BEAM
Presentation from Code BEAM STO on optimising Elixir and Erlang programs.
Michał Muskała
May 31, 2018
Tweet
Share
More Decks by Michał Muskała
See All by Michał Muskała
From Elixir to Erlang - Experience report
michalmuskala
0
37
What is the BEAM?
michalmuskala
0
50
Elixir & Ecosystem Update SF 2020
michalmuskala
0
20
Let there be light
michalmuskala
0
530
What actually is the BEAM?
michalmuskala
7
1.5k
Elixir - Exploring actor-based systems
michalmuskala
1
66
Extending OTP with custom behaviours
michalmuskala
0
92
Abandoning models - embracing data
michalmuskala
0
190
Ecto - the past, the present, the future
michalmuskala
5
1.1k
Other Decks in Programming
See All in Programming
料理の注文メニューの3D化への挑戦
hideg
0
290
AWS Config Custom Rule、ノーコードでできるかな?
watany
0
250
クラウド KMS の活用 / TOKYO BLOCKCHAIN TECH MEETUP 2022
odanado
PRO
0
190
ストア評価「2.4」だったCOCOARアプリを1年で「4.4」になんとかした方法@Cloud CIRCUS Meetup #2
1901drama
0
180
FutureCon 2022 FlutterアプリのPerformance測定
harukafujita
0
140
테라폼으로 ECR 관리하기 (How to Manage ECR with Terraform)
posquit0
0
530
SwiftUIで「意図」を伝える / swiftui_intention
uhooi
2
150
ECサイトの脆弱性診断をいい感じにやりたい/OWASPKansaiNight_LT1_220727
owaspkansai
0
290
NestJS_meetup_atamaplus
atamaplus
0
210
夕食断食にTRY!/for-lt-12th
pachikuriii
0
240
SAM × Dockerでサーバーレス開発が超捗った話
yu_yukk_y
1
350
kintoneでランダム取得を作ってみた(imoniCamp 2022-07-27)
shokun1108
0
150
Featured
See All Featured
How To Stay Up To Date on Web Technology
chriscoyier
780
250k
Scaling GitHub
holman
451
140k
Building Flexible Design Systems
yeseniaperezcruz
310
34k
It's Worth the Effort
3n
172
26k
Put a Button on it: Removing Barriers to Going Fast.
kastner
56
2.3k
Atom: Resistance is Futile
akmur
255
20k
Learning to Love Humans: Emotional Interface Design
aarron
261
37k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
316
19k
Build The Right Thing And Hit Your Dates
maggiecrowley
19
1.2k
Unsuck your backbone
ammeep
659
55k
Large-scale JavaScript Application Architecture
addyosmani
499
110k
Principles of Awesome APIs and How to Build Them.
keavy
113
15k
Transcript
OPTIMISING FOR THE BEAM
–Donald Knuth “premature optimization is the root of all evil”
–Donald Knuth “We should forget about small efficiencies, say about
97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.”
MICHAŁ MUSKAŁA Elixir & Ecto core team http://michal.muskala.eu/ https://github.com/michalmuskala/ @michalmuskala
OTP 21
WHY PERFORMANCE MATTERS
LEEX WITH BINARIES? https://github.com/michalmuskala/panacea
deflexer :lexer do defrule ignored, do: :skip defrule punctuator, meta(token:
token, line: line), do: {:token, {String.to_atom(token), line}} defrule reserved_word, meta(token: token, line: line), do: {:token, {String.to_atom(token), line}} defrule int_value, meta(token: token, line: line), do: {:token, {:int_value, line, String.to_integer(token)}} defrule float_value, meta(token: token, line: line), do: {:token, {:float_value, line, String.to_float(token)}} defrule string_value, meta(token: token, line: line), do: {:token, {:string_value, line, token}} defrule boolean_value, meta(token: token, line: line), do: {:token, {:boolean_value, line, String.to_atom(token)}} defrule name, meta(token: token, line: line), do: {:token, {:name, line, token}} end
CONTRIBUTION TO OTP & ELIXIR
JASON https://hex.pm/packages/jason
MEASURE-LEARN-REFACTOR
MONITOR
MONITOR observer observer_cli wobserver https://github.com/zhongwencool/observer_cli https://github.com/shinyscorpion/wobserver WombatOAM https://www.erlang-solutions.com/products/wombatoam.html
None
None
MEASURE
MEASURE fprof eprof cprof mix profile._prof xprof https://github.com/Appliscale/xprof
None
MICROBENCHMARK
MICROBENCHMARK :timer.tc/1 eministat benchee https://github.com/pragtob/benchee https://github.com/jlouis/eministat
None
None
NOT IN THE SHELL!!!
DISASSEMBLE
DECOMPILE $ erlc +to_asm foo.erl $ mix decompile Foo --to
asm https://github.com/michalmuskala/decompile https://happi.github.io/theBeamBook/
UNDERSTAND THE BEAM
REGISTER MACHINE
https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/ STACK VS REGISTER VM
SIMPLE MATHS
SIMPLE MATHS def test(a, b), do: a + b *
5 {function, test, 2, 10}. {label,10}. {gc_bif,'*',{f,0},2,[{x,1},{integer,5}],{x,1}}. {gc_bif,'+',{f,0},2,[{x,0},{x,1}],{x,0}}. return.
STACK ALLOCATION & TAIL RECURSION
STACK ALLOCATION & TAIL RECURSION defp id(x), do: x def
test(a, b), do: id(a) + id(b) {function, id, 1, 10}. {label,10}. return. {function, test, 2, 12}. {label,12}. {allocate,1,2}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {gc_bif,'+',{f,0},1,[{y,0},{x,0}],{x,0}}. {deallocate,1}. return.
STACK ALLOCATION & TAIL RECURSION defp id(x), do: x def
test(a, b), do: id(id(a) + id(b)) {function, test, 2, 12}. {label,12}. {allocate,1,2}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {gc_bif,'+',{f,0},1,[{y,0},{x,0}],{x,0}}. {call_last,1,{f,10},1}.
LITERALS
LITERALS test() -> [1, 2, #{a := 5}, foo]. {function,
test, 0, 2}. {label,2}. {move,{literal,[1,2,#{a => 5},foo]},{x,0}}. return.
INTEGER MATCHING - JUMP TABLE
INTEGER MATCHING - JUMP TABLE def test(x) do case x
do 0 -> "zero" 1 -> "one" 2 -> "two" end end {function, test, 1, 10}. {label,10}. {test,is_integer,{f,14},[{x,0}]}. {select_val,{x,0},{f,14}, {list,[{integer,0},{f,11}, {integer,1},{f,12}, {integer,2},{f,13}]}}. {label,11}. {move,{literal,<<"zero">>},{x,0}}. return. {label,12}. {move,{literal,<<"one">>},{x,0}}. return. {label,13}. {move,{literal,<<"two">>},{x,0}}. return. {label,14}. {case_end,{x,0}}.
PERFORMANCE TIPS
MACRO-INLINING digits = [{?0..?9, -?0}, {?A..?Z, 10 - ?A}, {?a..?z,
10 - ?a}] for {chars, diff} <- digits, char <- chars do digit = char + diff defp count_digits_nosign(<<unquote(char), rest::binary>>, base, count) when base > unquote(digit) do count_digits_nosign(rest, base, count + 1) end end defp count_digits_nosign(<<_::binary>>, _, count), do: count
DELEGATE TO BIFS def parse(binary, base) do case count_digits(binary, base)
do 0 -> :error count -> {digits, rem} = :erlang.split_binary(binary, count) {:erlang.binary_to_integer(digits, base), rem} end end
REUSE DATA IF NOT MODIFIED def delete(keywords, key) when is_list(keywords)
and is_atom(key) do :lists.filter(fn {k, _} -> k != key end, keywords) end def delete(keywords, key) when is_list(keywords) and is_atom(key) do case :lists.keymember(key, 1, keywords) do true -> delete_key(keywords, key) _ -> keywords end end defp delete_key([{key, _} | tail], key), do: delete_key(tail, key) defp delete_key([{_, _} = pair | tail], key), do: [pair | delete_key(tail, key)] defp delete_key([], _key), do: []
PROCESS BINARIES IN CHUNKS
def html_escape_to_iodata(data) when is_binary(data), do: to_iodata(data, 0, data, []) escapes
= [{?<, "<"}, {?>, ">"}, {?&, "&"}, {?\", """}, {?\', "'"}] for {match, insert} <- escapes do defp to_iodata(<<unquote(match), rest::bits>>, skip, original, acc) do to_iodata(rest, skip + 1, original, [acc | unquote(insert)]) end end defp to_iodata(<<_char, rest::bits>>, skip, original, acc), do: to_iodata(rest, skip, original, acc, 1) defp to_iodata(<<>>, _skip, _original, acc), do: acc for {match, insert} <- escapes do defp to_iodata(<<unquote(match), rest::bits>>, skip, original, acc, len) do part = binary_part(original, skip, len) to_iodata(rest, skip + len + 1, original, [acc, part | unquote(insert)]) end end defp to_iodata(<<_c, rest::bits>>, skip, orig, acc, len), do: to_iodata(rest, skip, orig, acc, len + 1) defp to_iodata(<<>>, 0, orig, _acc, _len), do: original defp to_iodata(<<>>, s, original, acc, len), do:[acc | binary_part(original, skip, len)]
DON’T USE DICT - USE MAPS
PREFER BIFS TO FUNCTIONS
PREFER BIFS TO FUNCTIONS • :binary.part to binary_part • :maps.get
to pattern matching to map_get • :maps.put to syntax
DREAMING ABOUT FUTURE
TAIL CALLS MODULO CONS
TAIL CALLS MODULO CONS map(F, [H|T]) -> [F(H)|map(F, T)]; map(F,
[]) when is_function(F, 1) -> [].
USE SSE INSTRUCTIONS IN SOME PARTS OF BEAM
UNROLLED LINKED LISTS
STORE DATA IN LITERAL AREA https://github.com/discordapp/fastglobal inspired by mochiglobal
MULTIPLE RETURN
OPTIMISING FOR THE BEAM