Grow and Shrink - Dynamically Extending the Ruby VM Stack

Grow and Shrink -
Dynamically Extending the
Ruby VM Stack
Ruby Kaigi 2018, Sendai, Japan
June 2nd, 2018
Keita Sugiyama (杉山敬太) and Martin J. Dürst
Aoyama Gakuin University (青山学院大学)
Speaker Introduction
• Keita Sugiyama (杉山 敬太)
Master Course Student
Intelligence and Information Course
Graduate School of Science and Engineering
Aoyama Gakuin University
(青山学院大学大学院理工学研究科知能情報コース M1)
• Martin J. Dürst
Department of Integrated Information Technology
College of Science and Engineering
Aoyama Gakuin University
(青山学院大学理工学部情報テクノロジー学科教授)
2
Looking for a summer
internship / 夏休みのイ
ンターンシップ検討中
Software Laboratory:
Past Contributions to Ruby
• Character encoding conversion
(String#encode, 2007)
• Unicode normalization
(String#normalize, 2014)
• Unicode upcase/downcase
(String#upcase,…, 2016)
• Update Unicode version
(Unicode 11.0.0 coming soon, see
https://bugs.ruby-lang.org/issues/14802)
3
Motivation: Multithread Ruby
• Concurrency ever more important
• Multi-core, languages such as Go and Elixir
• Efforts to make concurrency easier
in Ruby and MRI:
• Fibers, lazy, Guilds, MVM, thread cache,…
4
Herb Sutter. The free lunch is over: A fundamental turn toward concurrency in software.
http://www.gotw.ca/publications/concurrency-ddj.htm (viewed 2018/1/30).
耕一笹田, 行弘松本. Ruby 3 に向けた新しい並行実行モデルの提案. 情報処理学会論文誌プログラ
ミング (PRO), Vol. 10, No. 3, pp. 16–16, 06/16 2017.
Multithreading:
Memory Consumption
• Each Ruby VM thread needs a stack
• Stacks are large, fixed size (1MB)
to avoid stack overflow
• Many threads → many stacks → lots of memory
5
Dynamic extension of VM stacks
to save memory
For Code Geeks
• Implementation is published at:
github.com/sugiyama-k/ruby/tree/chaining
6
Outline
• Motivation
• The Ruby VM stacks
• Two extension methods:
Stretching and Chaining
• Safe and efficient development tips
• Experimental results
• Conclusions
7
Ruby VM Stacks
8
MRI
• Matz’s Ruby Interpreter
• Also called CRuby
• Ruby’s reference implementation
• Latest Stable Version: Ruby 2.5.1
• This work based on revision 60436
9
松本行弘ほか. オブジェクト指向スクリプト言語 Ruby. https://www.ruby-lang.org/ja/.
(2018/2/26 閲覧).
The Ruby Virtual Machine
• YARV(Yet Another Ruby VM)
• Developed by Koichi Sasada et al.
• Introduced with Ruby 1.9
• Uses two stacks
10
笹田耕一, 松本行弘, 前田敦司, 並木美太郎. Ruby 用仮想マシン YARV の実装と評価.
情報処理学会論文誌プログラミング(PRO), Vol. 47, No. SIG2(PRO28), pp. 57–73,
Feb 2006.
Dave Thomas, Chad Fowler, and Andy Hunt. Programming Ruby 1.9, Section 25.6.
The Pragmatic Programmers, 2009.
Pat Shaughnessy. Ruby Under a Microscope: An Illustrated Guide to Ruby Internals.
No Starch Press, 2013.
Ruby VM Stacks
11
lower addresses
higher addresses
overflow happens when
the two stacks meet
Call Stack
Internal Stack
Control
Frame
Stack Frame
Call Stack
• Array of control frames (6 words/48 bytes)
• One frame per invocation
(eval/class/method/block/cfunc)
12
Call Stack
Control
Frame
c:0001 p:0000 s:0003 E:001c60 (none)
c:0002 p:0016 s:0006 e:000005 EVAL fix.rb:5
c:0003 p:0008 s:0011 e:000010 METHOD fix.rb:2
c:0004 p:---- s:0016 e:000015 CFUNC :gsub
c:0005 p:0006 s:0020 e:000019 BLOCK fix.rb:2
def fix (st)
st.gsub(/b/) { |s| 'd'.show_stack }
end
fix 'abca'
Call Stack Example
13
Call Stack
file fix.rb
Object#show_stack
• Show stack even when there is no error in
the Ruby interpreter
• Works like Object#tap without a block
• Available as proof-of-concept patch
(https://bugs.ruby-lang.org/issues/14801)
14
Control Frame Structure
vm_core.h
15
typedef struct rb_control_frame_struct {
const VALUE *pc; /* program counter */
VALUE *sp; /* stack pointer */
const rb_iseq_t *iseq; /* instruction sequence */
VALUE self; /* self */
const VALUE *ep; /* environment pointer */
const void *block_code; /* ブロックへの命令構造体 */
} rb_control_frame_t;
Internal Stack
• One stack frame per control frame
• Variable size, overlapping
• Used for execution of instructions
16
Internal Stack Stack Frame
Stack Frame
17
cref_or_me
specval
type
Operand 1
Operand 2
operands
Environment Data
parameters and
local variables
Control Frame
Stack Pointer
Environment
Pointer
Access to Local Variables
18
Environment
Pointer
access by index
Local Variable
Environment
Data
Access to Local Variables
in Outer Scope
19
Frame where
Block is
defined
Block Framespecval points to
EP of outer scope
of block
access by index
Environment
Pointer
Environment
Pointer
Environment
Data
Environment
Data
Layout of Arguments
Passed to a Method
20
Argument 2
Argument 1
self
Argument 3
Environment
Data
Environment
Pointer
Environment
Pointer
Stack Pointer
Stack Pointer
Caller
Frame
Callee
Frame
Access to
Arguments from
Environment
Pointer
Arguments
to Method
Environment
Data
0015: 000000000000000b Integer: 5 <- Stack Pointer
0014: 000000000000000f Integer: 7
0013: 0000000000000009 Integer: 4
0012: 0000000000000007 Integer: 3
0011: 0000000011110003 (flags) <- Environment Pointer
0010: 0000000000000000 (specval)
0009: 00000006004b3240 (me_cref)
0008: 000000000000000f Integer: 7
0007: 0000000000000007 Integer: 3
0006: 0000000600096248 Object
0005: 0000000077770021 (flags) <- Environment Pointer
0004: 000000060013e3c1 (specval)
0003: 0000000000000000 (me_cref)
Internal Stack Example
def calc (n, x)
n + 4 * x **
5.show_stack
end
calc 3, 7
21
Internal Stack
file calc.rb
Execution Context Structure
22
typedef struct rb_execution_context_struct {
/* information about virtual machine */
VALUE *vm_stack; /* vm stack */
size_t vm_stack_size; /* stack size */
rb_control_frame_t *cfp; /* current
control frame */
/*
* omitted
*/
} rb_execution_context_t;
History of this Research
• Proposed by Koichi Sasada in 2016
• First attempt in 2016/7 by Sho Koike
only incomplete implementation
• Continued in 2017/8
23
小池翔. Ruby VM におけるスタック領域の拡張の提案と実装. 卒業研究論文,
青山学院大学, 2016.
Implementation
24
Stack Extension
• When a potential stack overflow is detected,
extend the stack to double its size
• To avoid infinite recursion
• Set a maximum stack size
• If maximum stack size is reached,
a stack overflow is triggered
25
Stretching the Stacks
• Keep structure of overall stack
• Allocate new memory area
• Copy call stack and internal stack
• Free old memory area
26
OverflowFree
Allocate
Copy
Copy
VM Stack Size
• Default Size: 1MB
About 10’000 recursions
• Use environment variables from trunk to set
maximum stack size
• RUBY_THREAD_VM_STACK_SIZE
• RUBY_FIBER_VM_STACK_SIZE
• Introduce new variables for initial stack size
• RUBY_THREAD_VM_STACK_INITIAL_SIZE
• RUBY_FIBER_VM_STACK_INITIAL_SIZE
• Reduce minimum size and alignment
27
Triggering Stack Extension
Change overflow check to call of stack
extension function
28
#define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin) 
if (!(((rb_control_frame_t *)((sp) + (margin)) + 1) 
>= (cfp))) {(void)0;} 
else vm_stackoverflow()
#define CHECK_VM_STACK_OVERFLOW0(ec, cfp, sp, margin) 
if (!(((rb_control_frame_t *)((sp) + (margin)) + 1) 
>= (cfp))) {(void)0;} 
else vm_stack_try_extend(ec, cfp, sp, margin)
Possible Places for Stack Extension
Functions where
CHECK_VM_STACK_OVERFLOW is called:
• invoke_iseq_block_from_c
• setup_parameters_complex
• vm_caller_setup_arg_splat
• vm_call0_body
• vm_push_frame_
• vm_call_method_missing
• vm_callee_setup_block_arg_arg0_splat
• vm_callee_setup_block_arg
29
Overview of
Stack Extension Processing
30
smaller than max size? stack overflow
deal with pointers:
• stack-internal
• execution context
stretching the stacks
decide new size
No
Yes
Dealing with Pointers to Stacks
Because the stacks move, pointers into the
stacks have to be fixed or changed.
• Stack-internal pointers,
pointers from execution context:
Adjust to point to new location
• ‘Unknown’ pointers:
Change referencing method
• Arguments to C functions:
Copy to C stack
31
Change of Referencing Method
• Before: Direct pointers
• After: Offsets from start of stack
• Conversion from offsets to pointers on access
32
offset into call stack
offset into internal stack
Conversion between
Pointers and Offsets
33
static inline ptrdiff_t
vm_stack_ptr_save(const rb_execution_context_t *ec,
const VALUE *ptr)
{
return ptr - ec->vm_stack;
}
static inline VALUE *
vm_stack_ptr_restore(const rb_execution_context_t *ec,
ptrdiff_t saved_ptr)
{
return ec->vm_stack + saved_ptr;
}
Arguments to C Functions
• Problem:
Passing arguments on Ruby internal stack
to C Functions that do not expect them to move
• Solution:
Copy arguments to separate location
34
/* (in function vm_call_cfunc_with_frame) */
argv = ALLOCA_N(VALUE, argc);
MEMCPY(argv, reg_cfp->sp + 1, VALUE, argc);
val = (*cfunc->invoker)(cfunc->func, recv, argc, argv);
Our
Development Method
35
A Simple Development Cycle
• Fix something
• Run tests
• Wait for a segmentation fault
• Have no idea why it occurred,
or how to reproduce it
36
Problems and Solutions
1. Segmentation faults are too late
→ Prohibit access to old stacks
2. Stack extensions occur too rarely
→ Frequent stack movement
Limited to development:
• Linux only
• #if VM_STACK_USE_MPROTECT
37
Prohibit Access to Old Stacks
• Instead of freeing, prohibit access to stack
• Use mprotect function
• Linux system call
• Controls access to memory pages
• Produces segmentation fault immediately
• Quickly discovers stack access that needs fixing
38
Michael Kerrisk. Linux プログラミングインタフェース. オライリー・ジャパン, 2012.
千住治郎 訳
Testing Stack Extension
• Problem:
Testing stack extension from a Ruby
program is difficult
• Stack extension occurs rarely
• Cannot trigger stack extension at specific point
in program execution
39
Explicit frequent triggering of stack
extension by implementation
Frequent Stack Movement
• Stack overflow is checked at 8 locations in MRI
• Move stack at every overflow check
(extend only if necessary)
• Allows to check that there are no locations
where stack extension may lead to bugs
40
Functional Test Results
• Version based on r60436 passes
make test-all
(17,429 tests, 2,232,108 assertions)
• Development version passes most tests,
except:
• Time-limited tests: Okay if limits increased
• One resource-limited tests
• Memory leak tests: Because we do not use free
41
Fully functional implementation
Evaluation of
Execution Speed
42
Execution Speed
• Using Ruby benchmarks
• Measure basic execution speed
• Influence of offset↔pointer conversions,…
• Stacks at default size, no extensions
43
Execution Environment
Each experiment is run 3 times;
the best time is used
44
CPU Intel x86_64 CPU Core i7-6500U 2.50GHz
memory 16GB
OS Gentoo Linux 4.12.5
compiler GCC(Gentoo 6.4.0 p1.1)
Ruby version ruby 2.5.0 dev(r60436)
Change of Execution Time
(relative)
45
0
0.5
1
1.5
2
Relativeexecutiontime
Stretching trunk
max Average
1.628 1.185
Reasons for Lower Speed
• Indirect access to call stack
• Frequent access to call stack
• VM instruction execution
• Method calls
• Block-related processing
46
Speedup can be expected
if control frames can stay in place
New Extension Method:
Chaining
Extension Method Call Stack Internal Stack
Stretching Grows downwards Grows upwards
Chaining Chain of control frames Grows upwards
47
Call Stack Chaining
• Call stack is implemented as a chain (linked list) of control
frames
• Stack overflow only happens for internal stack
• Internal stack is moved as before
• Based on Lua’s implementation
48
OverflowFree
Copy
Allocate
R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. The evolution of lua. In Proceedings of the Third ACM SIGPLAN
Conference on History of Programming Languages, HOPL III, pp. 2–1–2–26, New York, NY, USA, 2007. ACM.
Speedup with Chaining
49
0
0.5
1
1.5
2
Relativeexecutiontime
Stretching Chaining trunk
maximum average
Stretching 1.628 1.185
Chaining 1.349 1.068
Why is Chaining Still Slower?
• Moving of internal stack
• Access via offsets
• Copying arguments to C functions
• Dynamic allocation of control frames
Benchmarks with deep recursion tend to be
slower
50
More Evaluation Experiments:
Overview
• Change of execution time
• Influence of initial stack size
• Reduction of memory use
• Sleeping threads
• Influence of thread count
• Influence of initial stack size
• Recursive function invocation
to control thread depth
51
Change of execution time
when changing initial stack size
• Influence of shrinking initial stack size on
execution time
• Initial stack size
256 Bytes to 1MB, multiplying by 4
52
Relationship between Initial
Stack Size and Execution Time
(for Chaining)
53
0
0.2
0.4
0.6
0.8
1
1.2
1.4
Relativeexecutiontime
256B 1KB 4KB 16KB 64KB 256KB 1MB trunk
Initial stack size has almost no influence
on execution time
Evaluation of Memory Usage
• Change of memory usage due to stack
extension
• Influence of thread count
• Influence of initial stack size
• Initial stack size
• Baseline: 1MB(default)
• Our implementation: 1KB
54
Method of Evaluating
Memory Usage
• Using /usr/bin/time command
• Measuring maximum resident set size
• Generating many sleeping threads
55
(0..ARGV[0].to_i).map do |i|
Thread.new { sleep 100 }
end
Decrease in Memory Usage
baseline Stretching Chaining
Increase of memory
per thread
25.7KB 14.8KB 15.0KB
56
0
100
200
300
Maximummemory
usage[MB]
Number of threads
Stretching Chanining trunk
40 %
reduction
Changes of Memory Usage
Depending on Initial Stack Size
• Initial stack size:
Varying from 128B to 1MB, doubling
• Number of threads: 10,000
57
Relationship between Initial
Stack Size and Memory Usage
58
0
50
100
150
200
250
300
Maximummemoryusage[MB]
Initial Stack Size[B]
Stretching Chanining trunk
Greater memory savings
the smaller the initial stack size
Reasons for only Slightly
Lower Memory Usage
• Calculated memory usage:
1 MB × 10,000 = 10 GB
• Actual memory usage:
Only about 250 MB
• Large memory allocations just reserve virtual
memory
• Mapped to real memory only when actually used
59
the Linux Kernel Organization, Inc. overcommit-accounting, 4.14
edition, January 23 2018.
Memory Usage
with Actual Stack Extension
• 1024 threads
• Two models for stack depth distribution:
• Linear model
• Exponential model
60
Linear Model
• Thread 𝑛 uses 10𝑛 recursions
• Average number of recursions: 5125
61
recursions
stack
extensions
threads
10 1 1
20 2 1
30 2 1
40 3 1
…
10,240 10 1
Exponential Model
• When recursion depth doubles,
number of threads is halfed
• Average number of recursions: 60
• More realistic than linear model
62
recursions
stack
extensions
threads
10 0 512
20 1 256
40 2 128
80 3 64
…
10,240 10 1
Memory Usage with Actual
Stack Extension: Results
• Linear model: Memory increase with Chaining
• Exponential model: Memory decrease for both
Stretching and Chaining
63
Model
Maximum Memory Usage[MB]
Stretching Chaining trunk
Linear 375.5 550.4 348.0
Exponential 24.3 24.6 34.9
Reduction of memory usage
for a realistic model
Experiments: Caution
Ruby memory is abstracted by four layers
1. Ruby VM we are here
2. Allocator (glib malloc, jemalloc,…)
3. Operating System (virtual memory,…)
4. Hardware (cache,
translation lookaside buffer,…)
64
Nate Berkopec, Malloc Can Double Multi-threaded Ruby Program Memory Usage,
https://www.speedshop.co/2017/12/04/malloc-doubles-ruby-memory.html
Dynamic Stack Extension
in other Programming Languages
• Go, mruby, Lua, Perl
Dynamic stack extension
• Java
VM specification assumes extensible stack
• Python
Separate frame for each invocation
65
Summary
• Stable implementation of dynamic
Ruby VM stack extension
• Memory needs for highly multithreaded
programs reduced
• Chaining decreases speed by only 6.5%
66
What’s Next
• Further improve speed
Try to avoid slowdown for programs without threads
• Testing on many environments
• FreeBSD,…, Windows,…
• Avoid Linux-specific code
• Community involvement
• Your opinion matters
• Your data matters even more
67
Acknowledgements
• Koichi Sasada(笹田 耕一)
Idea and lots of advice
• Sho Koike(小池 翔)
First implementation attempt, mistakes we were able to learn from
• Shunichi Matsubara(松原 俊一)Yoshiyuki Shoji(莊司 慶行)
Help with research and talk preparation
• Yusuke Endo(遠藤 侑介)
Interesting discussions
• Anonymous reviewer(s)
Advice on experiments
68
1 of 68

Recommended

あなたのScalaを爆速にする7つの方法 by
あなたのScalaを爆速にする7つの方法あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法x1 ichi
9.1K views74 slides
Triton and Symbolic execution on GDB@DEF CON China by
Triton and Symbolic execution on GDB@DEF CON ChinaTriton and Symbolic execution on GDB@DEF CON China
Triton and Symbolic execution on GDB@DEF CON ChinaWei-Bo Chen
2.2K views111 slides
JCConf 2020 - New Java Features Released in 2020 by
JCConf 2020 - New Java Features Released in 2020JCConf 2020 - New Java Features Released in 2020
JCConf 2020 - New Java Features Released in 2020Joseph Kuo
366 views77 slides
Georgy Nosenko - An introduction to the use SMT solvers for software security by
Georgy Nosenko - An introduction to the use SMT solvers for software securityGeorgy Nosenko - An introduction to the use SMT solvers for software security
Georgy Nosenko - An introduction to the use SMT solvers for software securityDefconRussia
3.3K views48 slides
08 - Return Oriented Programming, the chosen one by
08 - Return Oriented Programming, the chosen one08 - Return Oriented Programming, the chosen one
08 - Return Oriented Programming, the chosen oneAlexandre Moneger
965 views32 slides
LCU14 209- LLVM Linux by
LCU14 209- LLVM LinuxLCU14 209- LLVM Linux
LCU14 209- LLVM LinuxLinaro
4K views27 slides

More Related Content

What's hot

Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016) by
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Igalia
522 views39 slides
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershell by
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershellCSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershell
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershellCanSecWest
1.9K views47 slides
Course lecture - An introduction to the Return Oriented Programming by
Course lecture - An introduction to the Return Oriented ProgrammingCourse lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented ProgrammingJonathan Salwan
1.7K views65 slides
JVM Memory Model - Yoav Abrahami, Wix by
JVM Memory Model - Yoav Abrahami, WixJVM Memory Model - Yoav Abrahami, Wix
JVM Memory Model - Yoav Abrahami, WixCodemotion Tel Aviv
1.4K views38 slides
Address/Thread/Memory Sanitizer by
Address/Thread/Memory SanitizerAddress/Thread/Memory Sanitizer
Address/Thread/Memory SanitizerPlatonov Sergey
6K views54 slides
Jvm profiling under the hood by
Jvm profiling under the hoodJvm profiling under the hood
Jvm profiling under the hoodRichardWarburton
3.4K views64 slides

What's hot(20)

Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016) by Igalia
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Igalia522 views
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershell by CanSecWest
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershellCSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershell
CSW2017 Amanda rousseau cansecwest2017_net_hijacking_powershell
CanSecWest1.9K views
Course lecture - An introduction to the Return Oriented Programming by Jonathan Salwan
Course lecture - An introduction to the Return Oriented ProgrammingCourse lecture - An introduction to the Return Oriented Programming
Course lecture - An introduction to the Return Oriented Programming
Jonathan Salwan1.7K views
CILK/CILK++ and Reducers by Yunming Zhang
CILK/CILK++ and ReducersCILK/CILK++ and Reducers
CILK/CILK++ and Reducers
Yunming Zhang1.3K views
Inside LoLA - Experiences from building a state space tool for place transiti... by Universität Rostock
Inside LoLA - Experiences from building a state space tool for place transiti...Inside LoLA - Experiences from building a state space tool for place transiti...
Inside LoLA - Experiences from building a state space tool for place transiti...
[JavaOne 2011] Models for Concurrent Programming by Tobias Lindaaker
[JavaOne 2011] Models for Concurrent Programming[JavaOne 2011] Models for Concurrent Programming
[JavaOne 2011] Models for Concurrent Programming
Tobias Lindaaker1.3K views
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly by Min-Yih Hsu
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu376 views
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson by AMD Developer Central
Low-level Shader Optimization for Next-Gen and DX11 by Emil PerssonLow-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
GTC16 - S6410 - Comparing OpenACC 2.5 and OpenMP 4.5 by Jeff Larkin
GTC16 - S6410 - Comparing OpenACC 2.5 and OpenMP 4.5GTC16 - S6410 - Comparing OpenACC 2.5 and OpenMP 4.5
GTC16 - S6410 - Comparing OpenACC 2.5 and OpenMP 4.5
Jeff Larkin1.7K views
Building High-Performance Language Implementations With Low Effort by Stefan Marr
Building High-Performance Language Implementations With Low EffortBuilding High-Performance Language Implementations With Low Effort
Building High-Performance Language Implementations With Low Effort
Stefan Marr4K views
Engineering fast indexes (Deepdive) by Daniel Lemire
Engineering fast indexes (Deepdive)Engineering fast indexes (Deepdive)
Engineering fast indexes (Deepdive)
Daniel Lemire7.4K views
Knit, Chisel, Hack: Building Programs in Guile Scheme (Strange Loop 2016) by Igalia
Knit, Chisel, Hack: Building Programs in Guile Scheme (Strange Loop 2016)Knit, Chisel, Hack: Building Programs in Guile Scheme (Strange Loop 2016)
Knit, Chisel, Hack: Building Programs in Guile Scheme (Strange Loop 2016)
Igalia475 views
CSW2017 Peng qiu+shefang-zhong win32k -dark_composition_finnal_finnal_rm_mark by CanSecWest
CSW2017 Peng qiu+shefang-zhong win32k -dark_composition_finnal_finnal_rm_markCSW2017 Peng qiu+shefang-zhong win32k -dark_composition_finnal_finnal_rm_mark
CSW2017 Peng qiu+shefang-zhong win32k -dark_composition_finnal_finnal_rm_mark
CanSecWest4.1K views

Similar to Grow and Shrink - Dynamically Extending the Ruby VM Stack

Android RenderScript on LLVM by
Android RenderScript on LLVMAndroid RenderScript on LLVM
Android RenderScript on LLVMJohn Lee
3.8K views26 slides
How Triton can help to reverse virtual machine based software protections by
How Triton can help to reverse virtual machine based software protectionsHow Triton can help to reverse virtual machine based software protections
How Triton can help to reverse virtual machine based software protectionsJonathan Salwan
414 views64 slides
Serverless on OpenStack with Docker Swarm, Mistral, and StackStorm by
Serverless on OpenStack with Docker Swarm, Mistral, and StackStormServerless on OpenStack with Docker Swarm, Mistral, and StackStorm
Serverless on OpenStack with Docker Swarm, Mistral, and StackStormDmitri Zimine
1.1K views53 slides
Enabling Java: Windows on Arm64 - A Success Story! by
Enabling Java: Windows on Arm64 - A Success Story!Enabling Java: Windows on Arm64 - A Success Story!
Enabling Java: Windows on Arm64 - A Success Story!Monica Beckwith
192 views32 slides
End to End Processing of 3.7 Million Telemetry Events per Second using Lambda... by
End to End Processing of 3.7 Million Telemetry Events per Second using Lambda...End to End Processing of 3.7 Million Telemetry Events per Second using Lambda...
End to End Processing of 3.7 Million Telemetry Events per Second using Lambda...DataWorks Summit/Hadoop Summit
3.1K views41 slides
Typesafe spark- Zalando meetup by
Typesafe spark- Zalando meetupTypesafe spark- Zalando meetup
Typesafe spark- Zalando meetupStavros Kontopoulos
542 views34 slides

Similar to Grow and Shrink - Dynamically Extending the Ruby VM Stack(20)

Android RenderScript on LLVM by John Lee
Android RenderScript on LLVMAndroid RenderScript on LLVM
Android RenderScript on LLVM
John Lee3.8K views
How Triton can help to reverse virtual machine based software protections by Jonathan Salwan
How Triton can help to reverse virtual machine based software protectionsHow Triton can help to reverse virtual machine based software protections
How Triton can help to reverse virtual machine based software protections
Jonathan Salwan414 views
Serverless on OpenStack with Docker Swarm, Mistral, and StackStorm by Dmitri Zimine
Serverless on OpenStack with Docker Swarm, Mistral, and StackStormServerless on OpenStack with Docker Swarm, Mistral, and StackStorm
Serverless on OpenStack with Docker Swarm, Mistral, and StackStorm
Dmitri Zimine1.1K views
Enabling Java: Windows on Arm64 - A Success Story! by Monica Beckwith
Enabling Java: Windows on Arm64 - A Success Story!Enabling Java: Windows on Arm64 - A Success Story!
Enabling Java: Windows on Arm64 - A Success Story!
Monica Beckwith192 views
Software Profiling: Understanding Java Performance and how to profile in Java by Isuru Perera
Software Profiling: Understanding Java Performance and how to profile in JavaSoftware Profiling: Understanding Java Performance and how to profile in Java
Software Profiling: Understanding Java Performance and how to profile in Java
Isuru Perera1.3K views
running stable diffusion on android by Koan-Sin Tan
running stable diffusion on androidrunning stable diffusion on android
running stable diffusion on android
Koan-Sin Tan285 views
Challenging Web-Scale Graph Analytics with Apache Spark by Databricks
Challenging Web-Scale Graph Analytics with Apache SparkChallenging Web-Scale Graph Analytics with Apache Spark
Challenging Web-Scale Graph Analytics with Apache Spark
Databricks965 views
Challenging Web-Scale Graph Analytics with Apache Spark with Xiangrui Meng by Databricks
Challenging Web-Scale Graph Analytics with Apache Spark with Xiangrui MengChallenging Web-Scale Graph Analytics with Apache Spark with Xiangrui Meng
Challenging Web-Scale Graph Analytics with Apache Spark with Xiangrui Meng
Databricks1.2K views
Genomic Computation at Scale with Serverless, StackStorm and Docker Swarm by Dmitri Zimine
Genomic Computation at Scale with Serverless, StackStorm and Docker SwarmGenomic Computation at Scale with Serverless, StackStorm and Docker Swarm
Genomic Computation at Scale with Serverless, StackStorm and Docker Swarm
Dmitri Zimine1.1K views
Porting a Streaming Pipeline from Scala to Rust by Evan Chan
Porting a Streaming Pipeline from Scala to RustPorting a Streaming Pipeline from Scala to Rust
Porting a Streaming Pipeline from Scala to Rust
Evan Chan4 views
CS6270 Virtual Machines - Java Virtual Machine Architecture and APIs by Kwangshin Oh
CS6270 Virtual Machines - Java Virtual Machine Architecture and APIsCS6270 Virtual Machines - Java Virtual Machine Architecture and APIs
CS6270 Virtual Machines - Java Virtual Machine Architecture and APIs
Kwangshin Oh2.7K views
High Performance Erlang - Pitfalls and Solutions by Yinghai Lu
High Performance Erlang - Pitfalls and SolutionsHigh Performance Erlang - Pitfalls and Solutions
High Performance Erlang - Pitfalls and Solutions
Yinghai Lu730 views
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ... by Lucidworks
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Solr Troubleshooting - Treemap Approach: Presented by Alexandre Rafolovitch, ...
Lucidworks1.7K views
Strata Singapore: Gearpump Real time DAG-Processing with Akka at Scale by Sean Zhong
Strata Singapore: GearpumpReal time DAG-Processing with Akka at ScaleStrata Singapore: GearpumpReal time DAG-Processing with Akka at Scale
Strata Singapore: Gearpump Real time DAG-Processing with Akka at Scale
Sean Zhong900 views
Using Smalltalk for controlling robotics systems by Serge Stinckwich
Using Smalltalk for controlling robotics systemsUsing Smalltalk for controlling robotics systems
Using Smalltalk for controlling robotics systems
Serge Stinckwich2.3K views
What’s Slowing Down Your Kafka Pipeline? With Ruizhe Cheng and Pete Stevenson... by HostedbyConfluent
What’s Slowing Down Your Kafka Pipeline? With Ruizhe Cheng and Pete Stevenson...What’s Slowing Down Your Kafka Pipeline? With Ruizhe Cheng and Pete Stevenson...
What’s Slowing Down Your Kafka Pipeline? With Ruizhe Cheng and Pete Stevenson...
HostedbyConfluent341 views

Recently uploaded

The details of description: Techniques, tips, and tangents on alternative tex... by
The details of description: Techniques, tips, and tangents on alternative tex...The details of description: Techniques, tips, and tangents on alternative tex...
The details of description: Techniques, tips, and tangents on alternative tex...BookNet Canada
110 views24 slides
Black and White Modern Science Presentation.pptx by
Black and White Modern Science Presentation.pptxBlack and White Modern Science Presentation.pptx
Black and White Modern Science Presentation.pptxmaryamkhalid2916
14 views21 slides
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum... by
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...NUS-ISS
28 views35 slides
DALI Basics Course 2023 by
DALI Basics Course  2023DALI Basics Course  2023
DALI Basics Course 2023Ivory Egg
14 views12 slides
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensorssugiuralab
11 views15 slides
Data-centric AI and the convergence of data and model engineering: opportunit... by
Data-centric AI and the convergence of data and model engineering:opportunit...Data-centric AI and the convergence of data and model engineering:opportunit...
Data-centric AI and the convergence of data and model engineering: opportunit...Paolo Missier
29 views40 slides

Recently uploaded(20)

The details of description: Techniques, tips, and tangents on alternative tex... by BookNet Canada
The details of description: Techniques, tips, and tangents on alternative tex...The details of description: Techniques, tips, and tangents on alternative tex...
The details of description: Techniques, tips, and tangents on alternative tex...
BookNet Canada110 views
Black and White Modern Science Presentation.pptx by maryamkhalid2916
Black and White Modern Science Presentation.pptxBlack and White Modern Science Presentation.pptx
Black and White Modern Science Presentation.pptx
maryamkhalid291614 views
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum... by NUS-ISS
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
NUS-ISS28 views
DALI Basics Course 2023 by Ivory Egg
DALI Basics Course  2023DALI Basics Course  2023
DALI Basics Course 2023
Ivory Egg14 views
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by sugiuralab
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors
sugiuralab11 views
Data-centric AI and the convergence of data and model engineering: opportunit... by Paolo Missier
Data-centric AI and the convergence of data and model engineering:opportunit...Data-centric AI and the convergence of data and model engineering:opportunit...
Data-centric AI and the convergence of data and model engineering: opportunit...
Paolo Missier29 views
STPI OctaNE CoE Brochure.pdf by madhurjyapb
STPI OctaNE CoE Brochure.pdfSTPI OctaNE CoE Brochure.pdf
STPI OctaNE CoE Brochure.pdf
madhurjyapb12 views
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu... by NUS-ISS
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
Architecting CX Measurement Frameworks and Ensuring CX Metrics are fit for Pu...
NUS-ISS32 views
Empathic Computing: Delivering the Potential of the Metaverse by Mark Billinghurst
Empathic Computing: Delivering  the Potential of the MetaverseEmpathic Computing: Delivering  the Potential of the Metaverse
Empathic Computing: Delivering the Potential of the Metaverse
Mark Billinghurst449 views
The Importance of Cybersecurity for Digital Transformation by NUS-ISS
The Importance of Cybersecurity for Digital TransformationThe Importance of Cybersecurity for Digital Transformation
The Importance of Cybersecurity for Digital Transformation
NUS-ISS25 views
SAP Automation Using Bar Code and FIORI.pdf by Virendra Rai, PMP
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdf
Igniting Next Level Productivity with AI-Infused Data Integration Workflows by Safe Software
Igniting Next Level Productivity with AI-Infused Data Integration Workflows Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Safe Software91 views
AI: mind, matter, meaning, metaphors, being, becoming, life values by Twain Liu 刘秋艳
AI: mind, matter, meaning, metaphors, being, becoming, life valuesAI: mind, matter, meaning, metaphors, being, becoming, life values
AI: mind, matter, meaning, metaphors, being, becoming, life values
Future of Learning - Khoong Chan Meng by NUS-ISS
Future of Learning - Khoong Chan MengFuture of Learning - Khoong Chan Meng
Future of Learning - Khoong Chan Meng
NUS-ISS31 views
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV by Splunk
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV
.conf Go 2023 - How KPN drives Customer Satisfaction on IPTV
Splunk86 views
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor... by Vadym Kazulkin
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
How to reduce cold starts for Java Serverless applications in AWS at JCON Wor...
Vadym Kazulkin70 views
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze by NUS-ISS
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng TszeDigital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
NUS-ISS19 views
Combining Orchestration and Choreography for a Clean Architecture by ThomasHeinrichs1
Combining Orchestration and Choreography for a Clean ArchitectureCombining Orchestration and Choreography for a Clean Architecture
Combining Orchestration and Choreography for a Clean Architecture
ThomasHeinrichs168 views
Spesifikasi Lengkap ASUS Vivobook Go 14 by Dot Semarang
Spesifikasi Lengkap ASUS Vivobook Go 14Spesifikasi Lengkap ASUS Vivobook Go 14
Spesifikasi Lengkap ASUS Vivobook Go 14
Dot Semarang35 views

Grow and Shrink - Dynamically Extending the Ruby VM Stack

  • 1. Grow and Shrink - Dynamically Extending the Ruby VM Stack Ruby Kaigi 2018, Sendai, Japan June 2nd, 2018 Keita Sugiyama (杉山敬太) and Martin J. Dürst Aoyama Gakuin University (青山学院大学)
  • 2. Speaker Introduction • Keita Sugiyama (杉山 敬太) Master Course Student Intelligence and Information Course Graduate School of Science and Engineering Aoyama Gakuin University (青山学院大学大学院理工学研究科知能情報コース M1) • Martin J. Dürst Department of Integrated Information Technology College of Science and Engineering Aoyama Gakuin University (青山学院大学理工学部情報テクノロジー学科教授) 2 Looking for a summer internship / 夏休みのイ ンターンシップ検討中
  • 3. Software Laboratory: Past Contributions to Ruby • Character encoding conversion (String#encode, 2007) • Unicode normalization (String#normalize, 2014) • Unicode upcase/downcase (String#upcase,…, 2016) • Update Unicode version (Unicode 11.0.0 coming soon, see https://bugs.ruby-lang.org/issues/14802) 3
  • 4. Motivation: Multithread Ruby • Concurrency ever more important • Multi-core, languages such as Go and Elixir • Efforts to make concurrency easier in Ruby and MRI: • Fibers, lazy, Guilds, MVM, thread cache,… 4 Herb Sutter. The free lunch is over: A fundamental turn toward concurrency in software. http://www.gotw.ca/publications/concurrency-ddj.htm (viewed 2018/1/30). 耕一笹田, 行弘松本. Ruby 3 に向けた新しい並行実行モデルの提案. 情報処理学会論文誌プログラ ミング (PRO), Vol. 10, No. 3, pp. 16–16, 06/16 2017.
  • 5. Multithreading: Memory Consumption • Each Ruby VM thread needs a stack • Stacks are large, fixed size (1MB) to avoid stack overflow • Many threads → many stacks → lots of memory 5 Dynamic extension of VM stacks to save memory
  • 6. For Code Geeks • Implementation is published at: github.com/sugiyama-k/ruby/tree/chaining 6
  • 7. Outline • Motivation • The Ruby VM stacks • Two extension methods: Stretching and Chaining • Safe and efficient development tips • Experimental results • Conclusions 7
  • 9. MRI • Matz’s Ruby Interpreter • Also called CRuby • Ruby’s reference implementation • Latest Stable Version: Ruby 2.5.1 • This work based on revision 60436 9 松本行弘ほか. オブジェクト指向スクリプト言語 Ruby. https://www.ruby-lang.org/ja/. (2018/2/26 閲覧).
  • 10. The Ruby Virtual Machine • YARV(Yet Another Ruby VM) • Developed by Koichi Sasada et al. • Introduced with Ruby 1.9 • Uses two stacks 10 笹田耕一, 松本行弘, 前田敦司, 並木美太郎. Ruby 用仮想マシン YARV の実装と評価. 情報処理学会論文誌プログラミング(PRO), Vol. 47, No. SIG2(PRO28), pp. 57–73, Feb 2006. Dave Thomas, Chad Fowler, and Andy Hunt. Programming Ruby 1.9, Section 25.6. The Pragmatic Programmers, 2009. Pat Shaughnessy. Ruby Under a Microscope: An Illustrated Guide to Ruby Internals. No Starch Press, 2013.
  • 11. Ruby VM Stacks 11 lower addresses higher addresses overflow happens when the two stacks meet Call Stack Internal Stack Control Frame Stack Frame
  • 12. Call Stack • Array of control frames (6 words/48 bytes) • One frame per invocation (eval/class/method/block/cfunc) 12 Call Stack Control Frame
  • 13. c:0001 p:0000 s:0003 E:001c60 (none) c:0002 p:0016 s:0006 e:000005 EVAL fix.rb:5 c:0003 p:0008 s:0011 e:000010 METHOD fix.rb:2 c:0004 p:---- s:0016 e:000015 CFUNC :gsub c:0005 p:0006 s:0020 e:000019 BLOCK fix.rb:2 def fix (st) st.gsub(/b/) { |s| 'd'.show_stack } end fix 'abca' Call Stack Example 13 Call Stack file fix.rb
  • 14. Object#show_stack • Show stack even when there is no error in the Ruby interpreter • Works like Object#tap without a block • Available as proof-of-concept patch (https://bugs.ruby-lang.org/issues/14801) 14
  • 15. Control Frame Structure vm_core.h 15 typedef struct rb_control_frame_struct { const VALUE *pc; /* program counter */ VALUE *sp; /* stack pointer */ const rb_iseq_t *iseq; /* instruction sequence */ VALUE self; /* self */ const VALUE *ep; /* environment pointer */ const void *block_code; /* ブロックへの命令構造体 */ } rb_control_frame_t;
  • 16. Internal Stack • One stack frame per control frame • Variable size, overlapping • Used for execution of instructions 16 Internal Stack Stack Frame
  • 17. Stack Frame 17 cref_or_me specval type Operand 1 Operand 2 operands Environment Data parameters and local variables Control Frame Stack Pointer Environment Pointer
  • 18. Access to Local Variables 18 Environment Pointer access by index Local Variable Environment Data
  • 19. Access to Local Variables in Outer Scope 19 Frame where Block is defined Block Framespecval points to EP of outer scope of block access by index Environment Pointer Environment Pointer Environment Data Environment Data
  • 20. Layout of Arguments Passed to a Method 20 Argument 2 Argument 1 self Argument 3 Environment Data Environment Pointer Environment Pointer Stack Pointer Stack Pointer Caller Frame Callee Frame Access to Arguments from Environment Pointer Arguments to Method Environment Data
  • 21. 0015: 000000000000000b Integer: 5 <- Stack Pointer 0014: 000000000000000f Integer: 7 0013: 0000000000000009 Integer: 4 0012: 0000000000000007 Integer: 3 0011: 0000000011110003 (flags) <- Environment Pointer 0010: 0000000000000000 (specval) 0009: 00000006004b3240 (me_cref) 0008: 000000000000000f Integer: 7 0007: 0000000000000007 Integer: 3 0006: 0000000600096248 Object 0005: 0000000077770021 (flags) <- Environment Pointer 0004: 000000060013e3c1 (specval) 0003: 0000000000000000 (me_cref) Internal Stack Example def calc (n, x) n + 4 * x ** 5.show_stack end calc 3, 7 21 Internal Stack file calc.rb
  • 22. Execution Context Structure 22 typedef struct rb_execution_context_struct { /* information about virtual machine */ VALUE *vm_stack; /* vm stack */ size_t vm_stack_size; /* stack size */ rb_control_frame_t *cfp; /* current control frame */ /* * omitted */ } rb_execution_context_t;
  • 23. History of this Research • Proposed by Koichi Sasada in 2016 • First attempt in 2016/7 by Sho Koike only incomplete implementation • Continued in 2017/8 23 小池翔. Ruby VM におけるスタック領域の拡張の提案と実装. 卒業研究論文, 青山学院大学, 2016.
  • 25. Stack Extension • When a potential stack overflow is detected, extend the stack to double its size • To avoid infinite recursion • Set a maximum stack size • If maximum stack size is reached, a stack overflow is triggered 25
  • 26. Stretching the Stacks • Keep structure of overall stack • Allocate new memory area • Copy call stack and internal stack • Free old memory area 26 OverflowFree Allocate Copy Copy
  • 27. VM Stack Size • Default Size: 1MB About 10’000 recursions • Use environment variables from trunk to set maximum stack size • RUBY_THREAD_VM_STACK_SIZE • RUBY_FIBER_VM_STACK_SIZE • Introduce new variables for initial stack size • RUBY_THREAD_VM_STACK_INITIAL_SIZE • RUBY_FIBER_VM_STACK_INITIAL_SIZE • Reduce minimum size and alignment 27
  • 28. Triggering Stack Extension Change overflow check to call of stack extension function 28 #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin) if (!(((rb_control_frame_t *)((sp) + (margin)) + 1) >= (cfp))) {(void)0;} else vm_stackoverflow() #define CHECK_VM_STACK_OVERFLOW0(ec, cfp, sp, margin) if (!(((rb_control_frame_t *)((sp) + (margin)) + 1) >= (cfp))) {(void)0;} else vm_stack_try_extend(ec, cfp, sp, margin)
  • 29. Possible Places for Stack Extension Functions where CHECK_VM_STACK_OVERFLOW is called: • invoke_iseq_block_from_c • setup_parameters_complex • vm_caller_setup_arg_splat • vm_call0_body • vm_push_frame_ • vm_call_method_missing • vm_callee_setup_block_arg_arg0_splat • vm_callee_setup_block_arg 29
  • 30. Overview of Stack Extension Processing 30 smaller than max size? stack overflow deal with pointers: • stack-internal • execution context stretching the stacks decide new size No Yes
  • 31. Dealing with Pointers to Stacks Because the stacks move, pointers into the stacks have to be fixed or changed. • Stack-internal pointers, pointers from execution context: Adjust to point to new location • ‘Unknown’ pointers: Change referencing method • Arguments to C functions: Copy to C stack 31
  • 32. Change of Referencing Method • Before: Direct pointers • After: Offsets from start of stack • Conversion from offsets to pointers on access 32 offset into call stack offset into internal stack
  • 33. Conversion between Pointers and Offsets 33 static inline ptrdiff_t vm_stack_ptr_save(const rb_execution_context_t *ec, const VALUE *ptr) { return ptr - ec->vm_stack; } static inline VALUE * vm_stack_ptr_restore(const rb_execution_context_t *ec, ptrdiff_t saved_ptr) { return ec->vm_stack + saved_ptr; }
  • 34. Arguments to C Functions • Problem: Passing arguments on Ruby internal stack to C Functions that do not expect them to move • Solution: Copy arguments to separate location 34 /* (in function vm_call_cfunc_with_frame) */ argv = ALLOCA_N(VALUE, argc); MEMCPY(argv, reg_cfp->sp + 1, VALUE, argc); val = (*cfunc->invoker)(cfunc->func, recv, argc, argv);
  • 36. A Simple Development Cycle • Fix something • Run tests • Wait for a segmentation fault • Have no idea why it occurred, or how to reproduce it 36
  • 37. Problems and Solutions 1. Segmentation faults are too late → Prohibit access to old stacks 2. Stack extensions occur too rarely → Frequent stack movement Limited to development: • Linux only • #if VM_STACK_USE_MPROTECT 37
  • 38. Prohibit Access to Old Stacks • Instead of freeing, prohibit access to stack • Use mprotect function • Linux system call • Controls access to memory pages • Produces segmentation fault immediately • Quickly discovers stack access that needs fixing 38 Michael Kerrisk. Linux プログラミングインタフェース. オライリー・ジャパン, 2012. 千住治郎 訳
  • 39. Testing Stack Extension • Problem: Testing stack extension from a Ruby program is difficult • Stack extension occurs rarely • Cannot trigger stack extension at specific point in program execution 39 Explicit frequent triggering of stack extension by implementation
  • 40. Frequent Stack Movement • Stack overflow is checked at 8 locations in MRI • Move stack at every overflow check (extend only if necessary) • Allows to check that there are no locations where stack extension may lead to bugs 40
  • 41. Functional Test Results • Version based on r60436 passes make test-all (17,429 tests, 2,232,108 assertions) • Development version passes most tests, except: • Time-limited tests: Okay if limits increased • One resource-limited tests • Memory leak tests: Because we do not use free 41 Fully functional implementation
  • 43. Execution Speed • Using Ruby benchmarks • Measure basic execution speed • Influence of offset↔pointer conversions,… • Stacks at default size, no extensions 43
  • 44. Execution Environment Each experiment is run 3 times; the best time is used 44 CPU Intel x86_64 CPU Core i7-6500U 2.50GHz memory 16GB OS Gentoo Linux 4.12.5 compiler GCC(Gentoo 6.4.0 p1.1) Ruby version ruby 2.5.0 dev(r60436)
  • 45. Change of Execution Time (relative) 45 0 0.5 1 1.5 2 Relativeexecutiontime Stretching trunk max Average 1.628 1.185
  • 46. Reasons for Lower Speed • Indirect access to call stack • Frequent access to call stack • VM instruction execution • Method calls • Block-related processing 46 Speedup can be expected if control frames can stay in place
  • 47. New Extension Method: Chaining Extension Method Call Stack Internal Stack Stretching Grows downwards Grows upwards Chaining Chain of control frames Grows upwards 47
  • 48. Call Stack Chaining • Call stack is implemented as a chain (linked list) of control frames • Stack overflow only happens for internal stack • Internal stack is moved as before • Based on Lua’s implementation 48 OverflowFree Copy Allocate R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. The evolution of lua. In Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages, HOPL III, pp. 2–1–2–26, New York, NY, USA, 2007. ACM.
  • 49. Speedup with Chaining 49 0 0.5 1 1.5 2 Relativeexecutiontime Stretching Chaining trunk maximum average Stretching 1.628 1.185 Chaining 1.349 1.068
  • 50. Why is Chaining Still Slower? • Moving of internal stack • Access via offsets • Copying arguments to C functions • Dynamic allocation of control frames Benchmarks with deep recursion tend to be slower 50
  • 51. More Evaluation Experiments: Overview • Change of execution time • Influence of initial stack size • Reduction of memory use • Sleeping threads • Influence of thread count • Influence of initial stack size • Recursive function invocation to control thread depth 51
  • 52. Change of execution time when changing initial stack size • Influence of shrinking initial stack size on execution time • Initial stack size 256 Bytes to 1MB, multiplying by 4 52
  • 53. Relationship between Initial Stack Size and Execution Time (for Chaining) 53 0 0.2 0.4 0.6 0.8 1 1.2 1.4 Relativeexecutiontime 256B 1KB 4KB 16KB 64KB 256KB 1MB trunk Initial stack size has almost no influence on execution time
  • 54. Evaluation of Memory Usage • Change of memory usage due to stack extension • Influence of thread count • Influence of initial stack size • Initial stack size • Baseline: 1MB(default) • Our implementation: 1KB 54
  • 55. Method of Evaluating Memory Usage • Using /usr/bin/time command • Measuring maximum resident set size • Generating many sleeping threads 55 (0..ARGV[0].to_i).map do |i| Thread.new { sleep 100 } end
  • 56. Decrease in Memory Usage baseline Stretching Chaining Increase of memory per thread 25.7KB 14.8KB 15.0KB 56 0 100 200 300 Maximummemory usage[MB] Number of threads Stretching Chanining trunk 40 % reduction
  • 57. Changes of Memory Usage Depending on Initial Stack Size • Initial stack size: Varying from 128B to 1MB, doubling • Number of threads: 10,000 57
  • 58. Relationship between Initial Stack Size and Memory Usage 58 0 50 100 150 200 250 300 Maximummemoryusage[MB] Initial Stack Size[B] Stretching Chanining trunk Greater memory savings the smaller the initial stack size
  • 59. Reasons for only Slightly Lower Memory Usage • Calculated memory usage: 1 MB × 10,000 = 10 GB • Actual memory usage: Only about 250 MB • Large memory allocations just reserve virtual memory • Mapped to real memory only when actually used 59 the Linux Kernel Organization, Inc. overcommit-accounting, 4.14 edition, January 23 2018.
  • 60. Memory Usage with Actual Stack Extension • 1024 threads • Two models for stack depth distribution: • Linear model • Exponential model 60
  • 61. Linear Model • Thread 𝑛 uses 10𝑛 recursions • Average number of recursions: 5125 61 recursions stack extensions threads 10 1 1 20 2 1 30 2 1 40 3 1 … 10,240 10 1
  • 62. Exponential Model • When recursion depth doubles, number of threads is halfed • Average number of recursions: 60 • More realistic than linear model 62 recursions stack extensions threads 10 0 512 20 1 256 40 2 128 80 3 64 … 10,240 10 1
  • 63. Memory Usage with Actual Stack Extension: Results • Linear model: Memory increase with Chaining • Exponential model: Memory decrease for both Stretching and Chaining 63 Model Maximum Memory Usage[MB] Stretching Chaining trunk Linear 375.5 550.4 348.0 Exponential 24.3 24.6 34.9 Reduction of memory usage for a realistic model
  • 64. Experiments: Caution Ruby memory is abstracted by four layers 1. Ruby VM we are here 2. Allocator (glib malloc, jemalloc,…) 3. Operating System (virtual memory,…) 4. Hardware (cache, translation lookaside buffer,…) 64 Nate Berkopec, Malloc Can Double Multi-threaded Ruby Program Memory Usage, https://www.speedshop.co/2017/12/04/malloc-doubles-ruby-memory.html
  • 65. Dynamic Stack Extension in other Programming Languages • Go, mruby, Lua, Perl Dynamic stack extension • Java VM specification assumes extensible stack • Python Separate frame for each invocation 65
  • 66. Summary • Stable implementation of dynamic Ruby VM stack extension • Memory needs for highly multithreaded programs reduced • Chaining decreases speed by only 6.5% 66
  • 67. What’s Next • Further improve speed Try to avoid slowdown for programs without threads • Testing on many environments • FreeBSD,…, Windows,… • Avoid Linux-specific code • Community involvement • Your opinion matters • Your data matters even more 67
  • 68. Acknowledgements • Koichi Sasada(笹田 耕一) Idea and lots of advice • Sho Koike(小池 翔) First implementation attempt, mistakes we were able to learn from • Shunichi Matsubara(松原 俊一)Yoshiyuki Shoji(莊司 慶行) Help with research and talk preparation • Yusuke Endo(遠藤 侑介) Interesting discussions • Anonymous reviewer(s) Advice on experiments 68

Editor's Notes

  1. ruby仮想マシンにおけるスタックの自動拡張についての発表を始めます.
  2. 近年はマルチスレッド処理が重要になっていることから Rubyにおいてもさまざまな面からスレッド処理の効率化がはかられています. 今回発表する仮想マシンのスタックの動的な拡張もマルチスレッド処理の効率化を目的としたものです.
  3. 私たちは,MRIにおけるマルチスレッドプログラムの実行時のメモリ使用量の削減を目的として, 仮想マシンのスタックに動的な拡張を実装しました. そのうえで,二つの実装手法による性能差を調べました. また,バグを含まない安全な実装を行うための手段や, メモリ使用量の削減と実行速度への影響の評価について説明します.
  4. まず,ruby仮想マシンについて説明します.
  5. mriはrubyのリファレンス実装で マッツ・ルビーインタプリタの略です. c言語による実装であることから,crubyとも呼ばれます. 最新安定版はruby2.5.1です. 本実装ではリビジョン60436を元に実装を行いました.
  6. mriで用いられる仮想マシンは笹田らによって開発された,yarvです. yarvはruby1.9で導入されました. yarvはスタックマシンであり, 二種類のスタックを使用します.
  7. 2種類のスタックはこの図のように ruby仮想マシンのスタック領域に配置されます. この発表では,Ruby Under a Microscopeという本にならって メモリアドレスの小さい側から,大きくなる方向に成長するスタックを,内部スタック, 反対方向に成長するスタックを,コールスタックと呼びます. 仮想マシンのスタックオーバフローは二つのスタックが衝突するときに発生します.
  8. スタック領域の上側から成長するコールスタックは, コントロールフレームという6ワードからなる構造体の配列です. この構造体は, メソッドやブロックの呼び出しなど,ひとつごとに用意されます.
  9. コントロールフレームはこのように定義されています. コントロールフレームはメンバとして,フレームごとの プログラムカウンタや,スタックポインタ,命令構造体,self,環境ポインタ,ブロックへの命令構造体を保持します.
  10. スタック領域の下側から成長する内部スタックには,コントロールフレーム毎に,スタックフレームが形成されます. それぞれのフレームのサイズは不定で,一部を重ね合わせて配置されます. 内部スタックは命令の実行に使われます.
  11. それぞれのスタックフレームはこの図のような構造になっていて,演算用の領域,環境データ,各フレームのローカル変数を記録する領域からなります. また,演算用の領域には,命令実行時にオペランドが記録されます. 対応するコントロールフレームのスタックポインタはスタック領域の次に使用する位置を指します. また,環境ポインタは環境データのもっとも上を指し示します. 次にスタックの使われ方について説明します.
  12. フレーム内のローカル変数には環境ポインタを基準にして,インデックスでアクセスします.
  13. ブロック内から,ブロックの外側のローカル変数へのアクセスは, 環境データ中のspecvalというデータを参照して行います. ブロックのフレームでは,specvalにはブロックが定義されたフレームの環境ポインタが記録されています. その環境ポインタを基準にして,ブロックが定義されたフレームのローカル変数にアクセスできます.
  14. メソッドの呼び出しでは呼び出しもとのフレームの上部の演算用の領域に,メソッドへの引数を配置し, その上に,メソッドのフレームを配置します. これにより,メソッドのフレームから,環境ポインタを基準にして,ローカル変数と同様に引数にアクセスできます.
  15. 仮想マシンのスタックと,現在のコントロールフレームへのポインタは実行コンテキスト構造体に記録されます. 実行コンテキスト構造体は,スレッドごとに用意される構造体で,実行の情報を記録します.
  16. この研究は2016年から笹田の協力のもと青山学院大学で始められました. 2016年に小池翔が仮想マシンスタックの実装しましたが, 一部のプログラムではセグメンテーション違反が発生したため, 十分な評価が行えませんでした 2017年から私が引き継いで研究を行いました.
  17. つぎに,スタック拡張の実装について説明します.
  18. スタックの拡張はスタックオーバフロー時にスタックを2倍に拡張します. ただし, 無限再帰のプログラムが実行され続けないように,スタックには最大サイズを設定し, それを超える場合は今までどおり例外を発生します.
  19. まずためしたストレッチ法は, スタックの構造を変更せずにスタックを伸ばす方法です. オーバフロー発生時に,新たな領域を確保し,それぞれのスタックをコピーします. 最後に元の領域を解放します.
  20. 仮想マシンのスタックはデフォルトで1メガバイトです. これは,およそ1万回の再帰ができるサイズです. MRIでは環境変数を用いて仮想マシン初期化時にスタックサイズを指定可能です. 仮想マシンのスタックサイズとして指摘可能な最小サイズは16KBです. これは,およそ180回再帰できるサイズです.
  21. スタック拡張を必要に応じて呼び出すために,スタックオーバフローを検知し,例外を発生するためのCHECK_VM_STACK_OVERFLOWマクロをスタック拡張の呼び出しに置き換えました.
  22. 拡張が起こる可能性のある箇所は,スタックオーバフローの確認に用いられるマクロであるCHECK_VM_STACK_OVERFLOWが使用されている箇所です. このような箇所は,実装中で8箇所あります. vm_push_frame_はコントロールフレームとスタックフレームの追加 それ以外はメソッドとブロックへの引数を内部スタック上に配置
  23. スタックの拡張処理は,主にこのような手順で行います. まずサイズを決定します. このとき,あらかじめ決めた最大サイズを超える場合は,通常のスタックオーバフローと同様に扱います. そうでない場合は,新たな領域にスタックをコピーします. 次に,元のスタックへのポインタを新たなスタックへのポインタに修正します. これは,仮想マシンスタック内に記録されたポインタと,実行コンテキスト構造体内のポインタについて行います.
  24. スタック拡張ではスタックが移動するため,スタックへのポインタが問題になります. スタック内へのポインタには主に三つのものがあります. ひとつめはスタック内や実行コンテキスト構造体内のポインタです. これらには,スタックの拡張時に新たなスタックをさすように修正することで対応します. もうひとつは,どこかわからない箇所からのポインタです. c言語のローカル変数として利用さえているものがこれに当たります. スタック拡張を実装する段階でこれらを発見して,スタックへの参照方法を問題の起こらない形に変更する必要があります 三つめは,cで定義されたメソッドへの引数として渡されるものです. これらは,あらかじめ別の領域にコピーすることで対応します.
  25. ローカル変数については, 実装の段階で,参照方法を変更する必要があります. 参照を保存するときにスタックの始点からのオフセットを保存し, アクセスするときに,スタックの始点とオフセットから参照先を計算します. 実行コンテキストに保存された,スタックの上端や下端へのポインタは拡張時に修正できるため, それらを基準にスタックにアクセスします.
  26. 内部スタックのポインタとオフセットの変換はこのように定義した関数で行っています. Vm_stack_ptr_saveは内部スタック内へのポインタをスタック視点からのオフセットに変換します. Vm_stack_ptr_restoreは逆の変換として,オフセットをスタックへのポインタに変換します. 内部スタックの始点は実行コンテキスト構造体ecにメンバvm_stackとして記録されています. このvm_stackはスタック拡張処理時に修正できるためこれを基準にしてアクセスします.
  27. また,メソッド呼び出しの処理には特別な対応が必要になります. これは,メソッドに引数の配列として内部スタックへのポインタが渡されるためです. 呼び出されるメソッドでは引数配列が移動することを想定していないので,メソッド実行中にスタックの拡張が行われた場合に問題になります. この問題を解決するため,引数をあらかじめalooca関数によって確保した領域にコピーし,それをメソッドに渡します.
  28. 次に,スタック拡張を実装する上で開発に用いた手段を説明します.
  29. 単純な開発手法としてはこのようなものが考えられます. まず,何か修正を行います. そして,テストを実行します. そして,セグメンテーションフォルトが発生するのを待ちます. 発生したエラーの原因や,再現するのは難しいです.
  30. この開発手法での問題はまず,セグメンテーションフォルトは遅すぎるというものです. エラーは問題箇所から離れた箇所で発生する可能性があるため,問題箇所の特定が難しくなります. そこで,問題のあるアクセスの直後にエラーを発生させるため,古いスタックへのアクセス禁止という方法を利用しました. 二つ目の問題は,スタックの拡張がまれにしか起こらないということです. そこで,頻繁にスタックを移動するという手段を用いました. これらは,開発時に限って利用します.
  31. ひとつめのは,古いスタックへのアクセス禁止は,スタックを解放する代わりにmprotect関数でアクセスを禁止する方法です. mprotect関数はシステムコールで,メモリページへのアクセス制御を行います. 元のスタックを開放する代わりにmprotect関数でスタック領域へのアクセスを禁止し, 拡張前のスタックにアクセスした直後にセグメンテーションエラーを発生させます. これにより,修正の必要があるスタックへのポインタを早期に発見できます.
  32. また,スタックの拡張は,rubyプログラムによるテストが困難です. スタックの拡張のテストのためにはあらゆるタイミングでのスタックの拡張が問題なく行えることを確認する必要がありますが. 実際に拡張が発生する回数は少なく,特定のタイミングで拡張を発生するのは困難です. そのため,実装時には意図的に拡張を頻発させてテストを行う必要があります.
  33. スタックの頻繁な移動は,スタックオーバフローが発生し,スタック拡張が行われる可能性のある箇所すべてでスタックを移動するというものです. このような箇所は実装中に8か所あり,それらの箇所で毎回スタックを移動します. また,必要な場合はスタックの拡張も行います. これを,とくに,前述の古いスタックへのアクセス禁止とあわせて行うことで,いつスタックの拡張が行われても問題の起こらない実装を行うことができます.
  34. mriのテストにより, およそ1万7千個のテスト,2,232,108 のアサーションを実行しました. 完成した実装では,すべてのテストに成功しました. 先ほどの開発手段を使用した状態で,ほとんどのテストに成功することを確認しました. 失敗したテストは,時間制限のあるテストがありますが,これらは制限を延長することで問題なく実行できることを確認しました. また,プロセスのリソースを制限するために失敗したものや,メモリリークにより失敗したテストがありましたが,これらは,スタックのfreeを行わなかったためです. このことから,問題の起こらない実装が行えていることを確認できました.
  35. 次に,評価実験いついて説明します.
  36. MRIのベンチマークにより実行速度の評価を行いました. スタック拡張の実装のために行った,スタックへのアクセス方法の変更による 実行速度への影響を確かめました. そのために,スタックの初期サイズをデフォルトのスタックサイズと同じにし, スタック拡張が起こらない状態での実行速度を評価します.
  37. 評価を行った環境はこの表のとおりです. Linuxで実験を行いました. 性能の評価はそれぞれ3回実行し, もっとも結果の良いものをデータに採用しました. まず,機能の評価の結果を説明します.
  38. こちらが結果の一部をグラフにしたものです. グラフの縦軸は,従来の実装との実行時間比で,値が大きいほど遅いことを示します. 最大で63%,全体の平均で19%の実行速度の低下でしたが, 実際には,グラフのようにばらつきがありました.
  39. 実行速度低下の原因として考えられるのは, コールスタックへのポインタを一部で間接的な参照に置き換えたことだと考えられます. コールスタック内へのポインタは,命令の実行処理や,メソッド呼び出しに関係する関数で使われるほか,ブロックの実装にも使われるので影響が大きくなります. このことから,コールスタックを移動させずに済む手法が有効であると考えました.
  40. そこで,新たな実装手法としてchainingを考えます. 先ほどの手法はスタックを引き伸ばすもので,コールスタックは下方向に,内部スタックは上方向に成長しました. 新たな,手法では,コールスタックをコントロールフレームの連結リストにし,内部スタックは上方向に成長します.
  41. この手法は, コールスタックをコントロールフレームの連結リストで実装する方法です. スタックの拡張は内部スタックのみについて行います. これは,Luaの実装を参考にしたものです. スタックがオーバフローしたときに,新たな領域を確保し,そこへ内部スタックをコピーします.
  42. こちらがベンチマークの結果をグラフにしたものです. 全体の平均での実行速度の低下は先ほど手法では19%でしたが,この手法では平均7%に改善されました.
  43. この手法での実行速度低下の原因として考えられるのは, 内部スタックへのポインタを間接的な参照に置き換えたことです. また,内部スタックが移動することからメソッドへの引数の別領域へのコピーも必要です. もう一つの原因はコントロールフレームの動的な確保です. コントロールフレームを動的に確保するため,再帰をおこなうベンチマークで実行速度の低下が確認されました.
  44. より詳しく性能を調べるため, スタックの初期サイズを変化させた場合の実行速度への影響を調べるための実験を行いました. また,メモリ使用量の削減を評価するため,sleepするだけのスレッドを大量に生成した場合と,再帰メソッドを実行するスレッドを生成した場合で評価を行いました. sleepするだけのスレッドを生成する実験ではメモリ使用量への影響を,スレッド数との関係と,初期スタックサイズとの関係について調べました.
  45. 最後に,初期スタックサイズによる実行時間の変化を評価します. 初期スタックサイズを縮小することによる実行速度への影響を評価するため, 初期スタックサイズを256Bから1MBまで4倍ずつ変化させて,MRIのベンチマークを実行しました.
  46. これは,チェイン法についての結果です. スタックの初期サイズによって実行時間がほとんど変化していないことがわかります. これは,スタックサイズが毎回2倍に拡大されるため,スタックの拡張が行われる回数が少ないためだと考えれます. したがって,スタックの拡張処理自体による実行速度の低下は小さく, 実行速度の低下の原因は,スタックへのアクセス方法の変更によると考えられます.
  47. つぎに,メモリ使用量の削減についての評価を示します. まず,スタックの初期サイズを縮小することによるメモリ使用量の削減を評価します. スタックの初期サイズは従来の実装ではデフォルトサイズである1mbとし, わたしたちによる二つの実装では1kbに設定しました.
  48. このような,評価ではこのような指定した数のスレッドを生成するプログラムを実行しました. そのうえで,timeコマンドによりプログラム実行時の最大物理メモリ使用量を計測しました. 生成するスレッドを1,000個から10,000個まで変化させた場合のメモし使用量を評価しました.
  49. 結果はこのグラフのようになりました. スレッドひとつあたりのメモリ使用量の増加は元の実装で25.7KBだったものがストレッチ法では14.8KB,チェイン法では15KBになりました. このことから,この実験では,どちらの手法でもメモリ使用量がおよそ40%削減されたことがわかりました. グラフからスレッド数が増えるにつれて,メモリ使用量の削減が大きくなることがわかります.
  50. 次に,初期スタックサイズを変化させることにより,メモリ使用量がどのように変化するかを評価しました. 初期スタックサイズを128バイトから1メガバイトまで2倍ずつ変化させ,メモリ使用量を計測しました. 生成するスレッド数は10,000個に設定しました.
  51. これが結果のグラフです. 初期スタックサイズが小さいほどメモリ使用量が小さくなる傾向にあることがわかります. また,初期スタックサイズの変化に対してメモリ使用量の変化は一定でないことがわかります. 大きなスタックサイズでは,ストレッチ法では従来の実装と同程度のメモリ使用量なのに対し, チェイン法ではメモリ使用量が少ないことがわかります.
  52. スレッドを一万個生成した場合,スタックには10GBのメモリが使用されますが, 実際の物理メモリの消費量はこれよりも少なく,およそ250MBです. これは, linuxのメモリアロケーションでは仮想メモリを割り当て, 物理メモリには実際に使用される領域のみをマッピングするためです. 同様の理由から大きなスタックサイズでのメモリ使用量に差が生じると考えられます. 従来の実装やストレッチ法では,スタック領域の両端から使用されるのに対し, チェイン法では下端のみが使用されるため,メモし使用量に差が生じると考えられます.
  53. より現実的なプログラムでのメモリ使用量を評価するため,スレッドを1024個生成し,それぞれでスタックの拡張が起きる場合での評価を行いました. スタックの深さの分布のモデルを二つ作成して評価しました. 一方ではスタックの深さを線形に分布させました. これを線形モデルとします. もう一方では,スレッドの数が半減するにつれ,スタックの深さを倍にしました. これを指数モデルとします.
  54. 線形モデルではn番目のスレッドの再帰回数を10nにしました. 再帰回数は10回から10240回になります. 平均の再帰回数は5125回です.
  55. 指数モデルでは10回再帰を512スレッドで,20回再帰を256スレッドで,40回再帰を128スレッドというように再帰回数を決定して実行しました. 最大の再帰回数は1スレッドでの10,240 回,平均の再帰回数は 60 回です. これは,実際の応用では浅いスタックのスレッドが頻繁に生成され,深いスタックのスレッドがまれにしか使われないことを反映したモデルです.
  56. 結果はこの表のようになりました. 線形モデルでは,スタック拡張を実装した場合にメモリ使用量が増加したことが分かる. これは,ストレッチ法では,スタック拡張処理時に一時的にスタック二つ分の領域を必要とするためであると考えられます. また,手法 2 ではコントロールフレームを動的に確保するため,コントロールフレーム数が多くなったときにメモリの無駄が増加すると考えられます. 指数モデルでは,わたしたちによる二つの実装について,元の実装に比べておよそ 30% のメモリ使用量の削減が確認されました. これはスタックの浅いスレッドが多かったために,線形モデルで問題になった要素の影響が小さく,全体でのメモリ使用量が削減されたためだと考えらます. このことから,実用的な応用において特によく見られるような,スタックの浅いスレッドの多い場合に,わたしたちで提案するスタックの自動拡張がメモリ使用量の削減に有効であると考えられます.
  57. [このスライドから Martin が発表します!!!!!] 実験において,注意すべき点があります. それは,Rubyのメモリ管理は四つの階層で抽象化されているということです. まず,一つ目の階層はRuby仮想マシンです. つぎに,アロケータの階層があります. さらに,OSでの仮想メモリの階層があり, 最後にハードウェアがあります.
  58. ほかの言語では多くの言語がスタックを動的に拡張します. Goや,mruby,Lua,Perlでは仮想マシンのスタックを動的に拡張します. また,Java仮想マシンは仮想マシンのスタックが動的に拡張されることを想定して設計されています. Pythonではスタックをフレームごとに用意するため,MRIのような問題はありません.
  59. わたしたちはMRIの機能を損なわずにスタックに動的な拡張を実装しました. MRIにおけるマルチスレッドプログラムの実行時のメモリ使用量を削減することを目的とし, スレッドを多数生成するプログラムでのメモリ使用量の削減を確認しました. また,処理速度は,チェイン法のほうが速いことがわかりました.
  60. 今後の課題の,一つ目は, 実行速度の改善です. スレッド数が少ない場合は,メモリ削減効果は小さいので, 拡張が起きない場合の性能低下が小さくなるように実装を改善する必要があります. 二つ目は, より多くの環境でのテストです. MRIは多くの環境での動作を想定していて,コンパイル時に設定可能なさまざまな要素があるため, 他のOSやコンパイル環境でのテストを行う必要があります.
  61. 開発や発表においてこちらのかたがたにご協力していただきました. ありがとうございます.