Show enters and exits. Hide enters and exits.
| 03:38:05 | evan | oooh |
| 03:38:09 | evan | facinating! |
| 03:38:10 | evan | http://gist.github.com/140407 |
| 03:39:22 | evan | you can see inlined methods inlining methods |
| 03:39:33 | evan | what a wonderful holiday gift that it seems to be working! |
| 03:50:57 | ddub | that looks like a lot of inlining |
| 03:51:43 | evan | yeah! awesome huh? |
| 03:53:45 | ddub | :) |
| 03:53:52 | evan | ddub: reload it |
| 03:53:55 | ddub | is it faster? |
| 03:53:59 | evan | it's got class names now too |
| 03:54:03 | evan | a bit easier to read |
| 03:54:06 | ddub | ooh, classy |
| 03:54:59 | evan | my simple test earlier showed a speed up from 18s to 15s |
| 03:55:08 | evan | i'm trying to get it working first |
| 03:55:18 | evan | then checking out the code it's generating |
| 03:55:20 | ddub | how does inlining play with inline caching? |
| 03:55:27 | evan | it's better |
| 03:55:42 | evan | and the ICs inform inlining |
| 03:55:49 | ddub | is it like objc where it inlines the cache result, or is the idea that there is a dependency on expiration? |
| 03:55:56 | evan | so if an IC said "hey, we called Symbol#to_s every time here" |
| 03:56:00 | evan | then when we compile that method |
| 03:56:04 | evan | we inline Symbol#to_s |
| 03:56:40 | evan | the ICs provide a way of saying "is the shit this time the same shit as last time?" |
| 03:56:48 | evan | so you can get to the target method ASAP |
| 03:57:04 | evan | dispatch wise, it looks like |
| 03:57:24 | evan | call ic_check_cache => call target_method |
| 03:57:38 | evan | with inlining, there are no calls, instead it's |
| 03:57:50 | evan | if obj.class.class_id == expected_class_id |
| 03:58:00 | evan | <code_for_target_method_here> |
| 03:58:03 | evan | else |
| 03:58:07 | ddub | ok, thats how I thought it would work |
| 03:58:10 | evan | return uncommon(); |
| 03:58:10 | evan | end |
| 03:58:55 | evan | each IC is a little database |
| 03:59:07 | evan | of receiver classes seen |
| 03:59:18 | evan | that informs the JIT on how to make the code awesome |
| 04:00:36 | ddub | is the class id check once per inlined call or once per compiled method? |
| 04:00:53 | evan | has to be once per inline call |
| 04:00:56 | evan | "call" |
| 04:01:16 | evan | because the reciever of the method isn't always the receiver of the inlined method |
| 04:01:35 | evan | def foo(a) a.bar; end |
| 04:01:48 | ddub | and no requirement that the inlined code won't mutate the method table, eh? |
| 04:01:51 | evan | the guard checks that a.class_id is the expected class id everytime |
| 04:02:16 | ddub | well I meant more like def foo(a) a.bar; a.baz; end |
| 04:02:30 | evan | where a.bar redefines a.baz |
| 04:02:38 | evan | ? |
| 04:03:11 | ddub | well, I was wondering whether if did two checks to make sure the class corresponding to 'a' hasn't mutated, or one |
| 04:03:24 | evan | well |
| 04:03:30 | evan | there is deoptimization |
| 04:03:33 | evan | that occurs on method changes |
| 04:03:43 | evan | so if foo inlines bar, and bar changes |
| 04:03:47 | evan | then we deoptimize foo |
| 04:04:07 | evan | but deoptimizing whene foo is currently running |
| 04:04:11 | evan | hm. |
| 04:04:15 | evan | i don't handle that currently. |
| 04:04:37 | ddub | yeah, that seems ... mind-blowing |
| 04:05:12 | evan | i wonder what the JVM does for that |
| 04:05:28 | ddub | ponders |
| 04:05:53 | evan | after each inlined method, i could check a flag in the CallFrame |
| 04:06:05 | evan | if it's set, bail to uncommon |
| 04:06:21 | evan | so after each inlining: |
| 04:06:31 | evan | if(call_frame->deoptimize_now) return uncommon(); |
| 04:06:48 | ddub | but.. that doesn't sound nearly as much fun as regenerating the method and rewriting the call stack |
| 04:07:03 | evan | i could set the flags by looking up the CallFrame chain to find runnings of methods that needs to be deoptimized |
| 04:07:12 | evan | you're right |
| 04:07:14 | evan | i'm a wus. |
| 04:07:19 | ddub | tsk tsk |
| 04:07:32 | ddub | take the easy way out now, I guarantee you'll have to swing back around for rubinius 3.0 |
| 04:07:40 | evan | hah |
| 04:07:52 | ddub | but perfect software never ships |
| 04:08:08 | ddub | what determines if a method is inlined? |
| 04:08:20 | evan | a couple things currently |
| 04:08:26 | evan | this is far from perfect yet |
| 04:08:32 | evan | 1) the IC contains one receiver |
| 04:08:42 | evan | so we know we only ever called one method |
| 04:09:05 | evan | 2) if the method is less than 20 instructions: it's small |
| 04:09:17 | evan | 3) less than 200: normal |
| 04:09:20 | evan | 4) otherwise large |
| 04:09:48 | evan | oh wait |
| 04:09:55 | evan | no no |
| 04:09:59 | evan | i've got the logic different |
| 04:10:03 | evan | anyway, it's based on size |
| 04:10:22 | evan | small methods are allowed to inline more than normal methods |
| 04:10:30 | evan | so that wrapper methods can inline their destination |
| 04:10:52 | evan | i'll need to do tests |
| 04:10:57 | evan | to figure out the right logic though |
| 04:11:28 | ddub | sounds like a job for benchmarking |
| 04:11:40 | evan | yep |
| 04:12:53 | evan | oh cooool! |
| 04:13:00 | evan | Hash#[] got inlined |
| 04:14:09 | evan | well, i'm off to dinner and a movie. |
| 04:14:21 | evan | perhaps a romantic comedy will enlight me into good inlining policies |
| 04:16:01 | ddub | inlining is hard |
| 04:16:15 | ddub | but the good news is that you don't have to get it perfect |
| 04:20:59 | slava | hi evan |