Show enters and exits. Hide enters and exits.
| 00:00:29 | headius | oh, I see |
| 00:00:40 | headius | the static inspection sees gsub and just marks a "needs heap scope" bit |
| 00:00:43 | headius | that's all |
| 00:00:58 | evan | and gsub sets it in the current scope |
| 00:01:01 | headius | yes |
| 00:01:04 | evan | k |
| 00:01:08 | headius | how do you do backref? |
| 00:01:21 | evan | using VariableScope.of_sender |
| 00:01:29 | evan | to get the callers VS |
| 00:01:30 | evan | then setting it |
| 00:01:32 | headius | ok, same basic thing |
| 00:01:36 | evan | as an ivar |
| 00:01:46 | headius | but I can eliminate the scopes, not sure if that's an option for you |
| 00:01:55 | evan | i think i'm going to generalize it into VS.set_backref |
| 00:02:02 | evan | so it can touch unmanaged memory |
| 00:02:10 | evan | VS.of_sender has to hoist the VS into managed memory |
| 00:02:21 | evan | which means the JIT can't assume as much |
| 00:02:36 | headius | yes |
| 00:02:41 | headius | it is teh suck |
| 00:02:52 | evan | well, CallFrame/scope elimination is what I did yesterday |
| 00:03:03 | headius | helping much? |
| 00:03:08 | evan | i got enough code exposed to LLVM that it can eliminate them entirely for leaf methods |
| 00:03:16 | evan | http://gist.github.com/123098 |
| 00:03:17 | evan | thats for |
| 00:03:20 | evan | def foo; 1; end |
| 00:03:36 | headius | that doesn't mean a whole lot to me |
| 00:03:41 | evan | the machine code at the bottom is what you wan to look at |
| 00:04:00 | evan | there is no ruby call frame info, it's all been eliminated |
| 00:04:04 | evan | it's just the argument check |
| 00:04:13 | evan | and then returning 0x3 (which is a tagged 1) |
| 00:04:14 | headius | ah |
| 00:04:23 | headius | I assume this only works for really trivial things |
| 00:04:27 | evan | leaves |
| 00:04:31 | evan | ie, no calls in the method |
| 00:04:38 | headius | leaves can produces exceptions though |
| 00:04:47 | headius | @@foo access that doesn't exist |
| 00:04:47 | evan | like... ? |
| 00:04:52 | headius | for example |
| 00:04:54 | evan | thats not a leaf |
| 00:04:55 | evan | for me |
| 00:04:59 | evan | since we raise that to a method call |
| 00:05:01 | headius | what's a leaf then? |
| 00:05:14 | evan | literals, self, ivars |
| 00:05:21 | headius | ahh |
| 00:05:24 | evan | not constants because of const_missing |
| 00:05:29 | headius | I should do that too |
| 00:05:34 | evan | it's a small step |
| 00:05:40 | evan | but it's moving us in the right direction |
| 00:05:53 | headius | I've been reticent to add more one-off optz since we're hopefully moving to a new compiler chain over the summer |
| 00:06:14 | headius | but yeah, that would make those methods essentially the same bytecode for us too |
| 00:06:17 | headius | er |
| 00:06:18 | headius | same asm |
| 00:06:21 | headius | so that's good |
| 00:06:25 | ddub | why cannot you inline known constants? |
| 00:07:04 | evan | ddub: thats true, i suppose i could have the interpreter keep some data on constant access |
| 00:07:21 | evan | to know it won't hit const_missing |
| 00:07:47 | evan | still have to look it up again |
| 00:07:53 | evan | because of the crazy constant repointing logic |
| 00:08:05 | headius | yes, can't inline without a guard anyway |
| 00:08:16 | evan | actually, since thats true, you stil might call const_missing |
| 00:08:21 | evan | because someone could do remove_const |
| 00:08:31 | headius | yep |
| 00:08:33 | ddub | remove_const? oh come on... |
| 00:08:39 | headius | no way to eliminate guard for const lookup |
| 00:08:43 | evan | ddub: i know, silly. |
| 00:08:48 | ddub | :) |
| 00:09:17 | headius | evan: ivar access when not set is supposed to produce a warning |
| 00:09:25 | headius | only hole I can think of in that set of leaf states |
| 00:09:41 | evan | yeah, meh on that warning. |
| 00:09:49 | evan | we've never generated it. |
| 00:09:49 | headius | FORK |
| 00:09:55 | evan | more like a SPORK |
| 00:10:02 | evan | because i'm gently cradling it |
| 00:10:02 | headius | good call |
| 00:10:06 | evan | but still have the ability to stab |
| 00:10:09 | ddub | KNORK |
| 00:10:21 | headius | I look forward to the day we decide to be less slavishly compatible |
| 00:10:43 | ddub | "now that we implemented everything, we are going to start removing the stupid bits" |
| 00:10:49 | ddub | "like modifiable constants" |
| 00:10:50 | evan | we've got round and around on whether warnings are part of the impl |
| 00:10:57 | evan | i don't even recall where we start now. |
| 00:11:09 | evan | s/start/stand/ |
| 00:11:18 | brixen | they don't change the computation so they are immaterial |
| 00:11:27 | evan | k |
| 00:13:09 | headius | I disagree, but I've learned not to try to convince you |
| 00:13:47 | evan | we've had this discussion every year for the past, mmm, this would make it 3 years |
| 00:13:53 | brixen | a very painful and long learning process headius |
| 00:14:38 | brixen | of course, I'm willing to consider cases in which they do change the computation |
| 00:14:45 | brixen | perhaps an app using expect |
| 00:15:15 | evan | man, shark really does not like profiling an app with JITd code |
| 00:15:18 | evan | geez. |
| 00:15:36 | brixen | it's probably totally confused |
| 00:15:42 | brixen | who is executing this code! |
| 00:16:00 | evan | it's like "UMM why does eip point to some random heap memory...." |
| 00:16:23 | evan | "Hey! Who put this here?!" |
| 00:16:44 | ddub | hmm |
| 00:16:58 | ddub | can you make remove_const just change the constant to undef ? :) |
| 00:17:10 | evan | heh |
| 00:17:16 | evan | undefined behavior alert! |
| 00:17:21 | evan | we'll output that warning |
| 00:17:54 | ddub | how about 'warning: if you are using remove_const you might want to consider a different career path' |
| 00:17:55 | evan | "Undefined Behavior Detected. Activating Tachyon Reflector." |
| 00:18:13 | ddub | 'warning: PI is exactly 4' |
| 00:18:19 | evan | hah |
| 00:31:40 | evan | dude, seriously |
| 00:31:46 | evan | shark has been trying for 30 minutes now. |
| 00:31:53 | evan | analyzing |
| 00:35:01 | headius | evan: how's that leaf optz helping perf? tested at all? |
| 00:35:10 | headius | I might just toss it in |
| 00:35:45 | evan | me |
| 00:35:46 | evan | meh. |
| 00:35:53 | evan | not a lot of methods that just return a number |
| 00:35:57 | evan | who would have thought, i know. |
| 00:36:01 | evan | </sarcasm> |
| 00:37:45 | headius | yeah |
| 00:37:49 | headius | I think that's why I never bothered |
| 00:38:06 | headius | it's pretty rare to have a method that just returns self or a literal or an ivar lookup |
| 01:33:29 | evan | wow. |
| 01:33:37 | evan | so Array#at in ruby, with the JIT |
| 01:33:46 | evan | is a shade faster than the primitive |
| 01:33:53 | ezmob | nice |
| 01:34:05 | evan | it's so small that it's probably stats noise |
| 01:34:40 | evan | it's still 2x faster than MRI |
| 01:34:45 | evan | in all cases :D |
| 01:34:48 | ezmob | ;) |
| 01:34:56 | ezmob | how hooked up is the jit now? |
| 01:35:03 | ezmob | jusy jitting simple stuff like array.at? |
| 01:35:05 | ezmob | or more? |
| 01:35:38 | evan | the specs run with the JIT on |
| 01:35:44 | evan | so it's running a lot. |
| 01:36:52 | ezmob | sweet |
| 01:38:03 | brixen | evan: yeah, I think we can start experimenting with removing the perf primitives and writing more in Ruby |
| 01:38:12 | evan | yep |
| 01:38:13 | brixen | which will be... awesome blossoms |
| 01:38:16 | evan | thats what i'm doing |
| 01:38:19 | brixen | sweet! |
| 01:38:40 | evan | turns out even an interpretered Array#at is pretty fine |
| 01:39:21 | brixen | nice |
| 01:40:58 | evan | http://gist.github.com/123361 |
| 01:41:10 | brixen | evan: some current jit results on the hash classes from this morning |
| 01:41:10 | brixen | http://spreadsheets.google.com/ccc?key=rdiNYWh0xTGShVHikWVmnUA |
| 01:41:15 | brixen | see the JIT tab |
| 01:41:18 | evan | primitive, interp, jit, mri / 3, mri |
| 01:42:53 | evan | brixen: who's jenxen? |
| 01:43:16 | headius | evan: got leaf optz in |
| 01:43:19 | brixen | evan: jenny |
| 01:43:44 | evan | ah ok. |
| 01:43:51 | headius | I remember the other reason I don't like adding these |
| 01:43:54 | brixen | evan: I was using her as a guinea pig to test sharing :) |
| 01:43:55 | headius | they only help benchmarks :D |
| 01:43:59 | evan | ah ah |
| 01:44:01 | headius | so I lose some benchmarks |
| 01:44:15 | evan | headius: are you just detecting the AST form? |
| 01:44:21 | headius | yes |
| 01:44:23 | evan | or did the JVM do the work |
| 01:44:27 | evan | ah, see thats where we're different |
| 01:44:29 | headius | well, JVM does a bunch more work |
| 01:44:30 | evan | i didn't DO anything |
| 01:44:35 | evan | LLVM did all that |
| 01:44:49 | brixen | evan: the interesting column are in purple, they basically compare how much faster the jit made 2 different hash impls |
| 01:45:06 | headius | evan: sure, that's not easily visible to jvm atm |
| 01:45:19 | headius | some of our optz we have to do above the level of bytecode for now |
| 01:45:45 | headius | it's not a big deal |
| 01:45:53 | evan | yeah |
| 01:46:02 | evan | i didn't do that because i wanted super fast leaf methods |
| 01:46:04 | evan | though thats nice |
| 01:46:15 | evan | I did it to figure out how to give LLVM the proper visibility |
| 01:46:21 | headius | sure |
| 01:47:56 | headius | the lack of visibility for hotspot is largely why --fast exists |
| 01:48:04 | headius | and why we're doing a better compiler this summer |
| 01:49:12 | headius | don't get me wrong...I envy you LLVM :) |
| 01:49:22 | headius | I wish we had the same, but writing our own will be fun too |
| 01:49:27 | evan | yeah |
| 01:49:38 | evan | having alloca operations has been key |
| 01:49:44 | headius | right |
| 01:49:53 | evan | is the JVM doing escape analysis? |
| 01:49:55 | headius | java 6 update 14 has escape analysis which will help some of this |
| 01:49:59 | headius | bing |
| 01:50:02 | headius | yes |
| 01:50:11 | headius | but of course we defeat some of that with current prealloc optz |
| 01:50:33 | headius | prealloc makes them nearly as cheap as alloca'ed frames, but it interferes with eliminating access at all |
| 01:51:19 | evan | yeah |
| 01:51:21 | headius | actually, it's probably cheaper than alloca'ed frames since there's no alloc at all |
| 01:51:30 | headius | but it's kinda gross |
| 01:51:30 | evan | the thing about alloca is giving the compiler full visibility and control over the data structure |
| 01:51:35 | evan | so it can fully reason about it |
| 01:51:36 | headius | right |
| 01:51:47 | evan | and make wide assumptions |
| 01:51:49 | headius | the equivalent for us would be to add arguments to the call path |
| 01:51:59 | headius | but propagating that is unpleasant |
| 01:52:29 | headius | may be easier with invokedynamic |
| 01:53:33 | evan | you mean passing everything as arguments |
| 01:53:47 | evan | so you force them to be in the jvm call frame |
| 01:54:06 | headius | right |
| 01:54:14 | headius | in which case it just eliminates them if they're not used |
| 01:55:01 | evan | gotcha |
| 01:55:05 | headius | I think we can get almost all of it via better compilation though |
| 01:55:12 | headius | --fast runs rails, for example |
| 01:55:15 | evan | one thing i was doing at the same time was cleaning up the CallFrame |
| 01:55:23 | evan | to exclude things that were available as arguments |
| 01:55:33 | evan | ie, i was doing a bunch of data movement for no reason |
| 01:55:37 | headius | yeah |
| 01:55:53 | headius | I saw a couple of those commits |
| 01:56:37 | evan | doing that helped too |
| 01:56:48 | evan | because LLVM's value numbering figures stuff out |
| 01:56:50 | evan | so things |
| 01:56:51 | evan | like |
| 01:56:56 | evan | def foo(a); a; end |
| 01:56:58 | evan | which is stupid |
| 01:57:22 | evan | but you can see how LLVM reduces that to doing a memory access to get a as an argument |
| 01:57:25 | evan | and returning it |
| 02:00:08 | headius | sure |
| 02:00:13 | evan | ARG |
| 02:00:20 | evan | fucking A people. |
| 02:00:29 | evan | someone put another copy of Array#at in common |
| 02:00:33 | evan | ok, forget everything I said. |
| 02:00:35 | evan | lets retest. |
| 02:04:32 | evan | ok |
| 02:04:36 | evan | well, it's not as good |
| 02:04:43 | evan | but the results are more what I figured they'd be |
| 02:05:17 | evan | primitive is about 4.5x faster than interpreted |
| 02:05:26 | evan | primitive is 2x faster than JIT |
| 02:05:28 | evan | so thats good |
| 02:05:37 | evan | within striking distance |
| 02:10:13 | evan | nice |
| 02:10:19 | evan | conditionalizing calling Type.coerce_to helped |
| 02:19:06 | slava | hi evan |
| 02:19:21 | evan | hey there |
| 02:42:21 | rue | OK, new rule |
| 02:42:48 | rue | When you glance at the mirror and for a couple microseconds wonder who that guy is, it is bedtime |
| 02:44:13 | evan | haha |
| 02:44:14 | evan | so true |
| 02:44:16 | evan | i've done that. |
| 02:44:30 | evan | "OMG guy looking in my house! On the... 3rd floor, ah shit it's me." |
| 02:48:18 | mernen | catching up with the discussion before |
| 02:49:11 | mernen | regarding constants, the value of a constant lookup can change even without undef/const_missing, because of the scoping rules |
| 02:49:53 | mernen | so yeah, I guess it's impossible to optimize them without guards (just reinforcing that conclusion) |
| 02:50:30 | slava | what if you handle constant changes with some kind of de-optimization technique instead of explicit checks? |
| 02:51:18 | mernen | I guess that's possible too |
| 02:51:24 | rue | Quite possibly better |
| 02:51:37 | slava | like, if a constant is redefined, checkpoint all threads, update machine code references to the constant with the new value, and resume threads |
| 02:51:38 | mernen | an example of what I was talking about: http://gist.github.com/123362 |
| 02:51:47 | slava | how often do ruby programs change constants at runtime? |
| 02:51:52 | slava | is this just a development thing? |
| 02:51:56 | slava | or do people have inner loops that do this? :) |
| 02:53:03 | mernen | these are extreme cases, as far as I know |
| 02:53:29 | slava | don't penalize the common case then |
| 02:53:38 | mernen | not common at all, though I have already seen people using remove_const in production code |
| 02:54:42 | mernen | afaik, both jruby and YARV cache const values, using a global constant change counter to check |
| 02:55:03 | mernen | i.e., (un)defining any constant instantly invalidates all caches |
| 02:55:42 | mernen | since in the vast majority of cases constants never change after bootup, this is very effective |
| 02:56:21 | slava | a global counter is still a conditional branch and extra memory load |
| 02:56:28 | slava | would be neat if there was a way to avoid that |
| 16:13:52 | jcoglan | hey guys |
| 16:15:02 | jcoglan | quick compilation problem... |
| 16:15:39 | jcoglan | trying to build on Ubuntu, tail of my build output looks like this: |
| 16:15:39 | jcoglan | vm/builtin/system.cpp: In static member function ‘static rubinius::Object* rubinius::System::vm_jit_info(rubinius::VM*)’: |
| 16:15:39 | jcoglan | vm/builtin/system.cpp:316: error: incomplete type ‘rubinius::LLVMState’ used in nested name specifier |
| 16:15:39 | jcoglan | vm/builtin/system.cpp:319: error: invalid use of incomplete type ‘struct rubinius::LLVMState’ |
| 16:15:39 | jcoglan | vm/shared_state.hpp:29: error: forward declaration of ‘struct rubinius::LLVMState’ |
| 16:15:41 | jcoglan | vm/builtin/system.cpp:320: error: invalid use of incomplete type ‘struct rubinius::LLVMState’ |
| 16:15:43 | jcoglan | vm/shared_state.hpp:29: error: forward declaration of ‘struct rubinius::LLVMState’ |
| 16:15:45 | jcoglan | vm/builtin/system.cpp:321: error: invalid use of incomplete type ‘struct rubinius::LLVMState’ |
| 16:15:47 | jcoglan | vm/shared_state.hpp:29: error: forward declaration of ‘struct rubinius::LLVMState’ |
| 16:15:49 | jcoglan | rake aborted! |
| 16:15:51 | jcoglan | Command failed with status (1): [gcc -Ivm/external_libs/libtommath -Ivm/ext...] |
| 16:22:27 | gnufied | jcoglan, i am getting the same error. I thought some forward declaration was missing. |
| 16:30:41 | jcoglan | gnufied -- okay, I guess HEAD is broken. will try some older commits |
| 16:51:22 | ddub | have you ever tried searching for yourself on wikipedia? http://en.wikipedia.org/wiki/David_Waite |
| 16:53:06 | brixen | ddub: funny, you look much younger in person :) |
| 17:04:13 | rue | Probably missing a conditional define |
| 17:05:20 | gnufied | rue, for fixing that compile error? |
| 17:15:10 | lypanov | wibbles |
| 17:15:30 | brixen | hey lypanov |
| 17:15:35 | lypanov | can't decide if he should hack on rubinius or jruby next week |
| 17:15:52 | brixen | um, that shouldn't be too hard to decide |
| 17:15:59 | brixen | rbx is soo much more fun :) |
| 17:15:59 | lypanov | whats speed like in rubinius vs mri now? |
| 17:16:09 | brixen | depends what you are doing |
| 17:16:21 | lypanov | microbenchmarks :P |
| 17:16:23 | brixen | the specs run in 3-6x mri |
| 17:16:30 | brixen | ahh microbenchmarks |
| 17:16:35 | brixen | you're in luck :) |
| 17:16:40 | brixen | we should be much faster |
| 17:17:11 | lypanov | lol |
| 17:17:12 | lypanov | w00t |
| 17:17:26 | lypanov | whats a good microbenchmark for me to hack on? |
| 17:17:53 | lypanov | i'd like to work on improving performance of array iterators |
| 17:18:00 | brixen | hm, you could compare calling a method in ruby to calling a method in C |
| 17:18:12 | brixen | see if there is any room to lean up the call path further |
| 17:18:24 | lypanov | lots :P |
| 17:18:40 | brixen | we there ya go :) |
| 17:18:46 | brixen | s/we/well/ |
| 17:39:25 | boyscout | Conditionalize use of LLVMState. - cb98565 - Brian Ford |
| 17:39:31 | brixen | gnufied: that should fix your build |
| 17:40:07 | brixen | at this point, we should probably just make LLVM a dep |
| 17:40:22 | brixen | it's not like we're going to remove the jit :) |
| 17:48:36 | lypanov | dgtized: around? |
| 17:52:27 | dgtized | lypanov: yup |
| 17:53:06 | lypanov | dgtized: i seem to recall you had interest in some more advanced optimisations and wondered if you had made much progress / brainstormed on it / had interest in talking about it? |
| 17:54:10 | dgtized | well it depends on where they go -- evan recently added some block inlining type code that really improves performance on things like Array#each |
| 17:54:11 | brixen | lypanov: implement equality saturation :) |
| 17:54:32 | lypanov | equality saturation? |
| 17:54:57 | lypanov | dgtized: ah! very nice. generic or specific to a few types? how does it work? can you remember commit num? |
| 17:55:03 | lypanov | greps through log |
| 17:55:46 | dgtized | lypanov: it's somewhere in the LLVM JIT code, which unfortunately I haven't had a chance to learn |
| 17:56:46 | dgtized | it gives us a 4x speedup over MRI for Array#each however |
| 17:56:54 | brixen | boggles that lypanov has not heard of eqsat |
| 17:56:56 | brixen | lypanov: http://www.cse.ucsd.edu/~rtate/publications/eqsat/ |
| 17:57:33 | evan | morning |
| 17:57:34 | brixen | lypanov: if you could add that to LLVM, kthxbye |
| 17:57:40 | brixen | morning |
| 17:59:50 | ddub | morning |
| 18:11:44 | lypanov | brixen: um |
| 18:12:01 | lypanov | brixen: love the domain/lang specific opts side of this |
| 18:12:12 | evan | dgtized: it's not a 4x speed up OVER MRI |
| 18:12:22 | evan | dgtized: it's a 4x speed up over previous rubinius code |
| 18:12:33 | lypanov | which is nx time faster already? |
| 18:12:43 | evan | no |
| 18:12:48 | evan | for Array#each, we were slower |
| 18:12:57 | evan | we're now about 50% faster |
| 18:13:06 | lypanov | very nice |
| 18:13:08 | lypanov | what cases? |
| 18:13:15 | evan | just Array#each |
| 18:13:16 | evan | ! |
| 18:13:18 | evan | :) |
| 18:13:20 | lypanov | generic or microbenchmark? |
| 18:13:26 | evan | micro |
| 18:13:38 | evan | but the opt is generic |
| 18:13:39 | lypanov | can you remember the spec in question? |
| 18:13:54 | lypanov | i suppose i need to get the dang thing compiling first |
| 18:13:58 | evan | the benchmark I tested with is benchmark/rubinius/bm_array_each.rb |
| 18:14:00 | lypanov | cleans and retries a debug build |
| 18:14:05 | evan | which is silly |
| 18:14:14 | evan | but exercises the hell out of Array#each |
| 18:14:32 | evan | the opt was to give the JIT knowledge about Tuple#at |
| 18:14:52 | evan | so it could see Tuple#at was being used, and emit a type guard and then assembly thats the equiv of Tuple#at directly |
| 18:15:04 | lypanov | how did you do jitted profiling? |
| 18:15:17 | brixen | lypanov: yes, the domain axioms are the delicious part of eqsat |
| 18:15:19 | evan | how do ya mean? |
| 18:15:41 | brixen | lypanov: and the boolean sat solvers have gotten really fast and sophisticated in the last few years |
| 18:16:18 | lypanov | evan: i mean. is there an interp/compiler level profiler that gives info on what generated the code that was slow |
| 18:16:32 | lypanov | or do you only have user level profiling, as in, profiling of what is slow in apps? |
| 18:16:40 | lypanov | wonders if that makes sense |
| 18:16:51 | lypanov | rubydium does two styles, one in which it gives the call stack for the program |
| 18:17:05 | lypanov | another in which in uses the call stack for the compiler for any given line of generated asm |
| 18:17:13 | evan | lypanov: we've got a profiler builtin that we use |
| 18:17:21 | lypanov | makes it easy to find out what is generating shit code |
| 18:17:24 | evan | thats at the VM level |
| 18:17:53 | lypanov | very cool |
| 18:18:06 | evan | interesting, so you were profiling the generated code using what? |
| 18:18:32 | lypanov | a hash storing counters |
| 18:18:43 | lypanov | the hash key was the call stack for the generated instruction |
| 18:18:50 | lypanov | inced whenever that intruction was executed |
| 18:19:08 | evan | each x86 instruction did this?! |
| 18:19:24 | lypanov | aye. mega slow mode hehe |
| 18:19:47 | evan | WOW. |
| 18:19:51 | evan | what info did that give you? |
| 18:20:07 | lypanov | call stacks for the heavy parts of things |
| 18:20:15 | lypanov | eg, stack push/pop. register lookup. etc |
| 18:20:32 | lypanov | s/register/variable/ |
| 18:20:33 | evan | call stacks being... a stack trace? |
| 18:20:57 | lypanov | aye. sorry |
| 18:21:36 | evan | interesting. |
| 18:21:52 | lypanov | i did some neat things with the resulting stacks by changing the filter used on the "stack" generator |
| 18:22:02 | lypanov | to get me method level profile hashes easily |
| 18:22:43 | evan | strange |
| 18:22:53 | evan | my brain still doesn't get what data that shows ya... |
| 18:23:11 | lypanov | as in, instead of caller i'd use caller[-3..-1] etc |
| 18:23:40 | dgtized | evan: Array#each on MRI on my machine is 4.06 user time versus 0.944 user time on rubinius + jit, and 1.66 or so on rubinius without jit |
| 18:23:41 | lypanov | and that would give me the high level overview of which methods in the vm where using most of the actual execution time |
| 18:23:55 | evan | dgtized: wow! |
| 18:23:58 | evan | dgtized: nevermind then! |
| 18:24:00 | evan | yay! |
| 18:24:01 | lypanov | evan: it basically will tell you which instrinsics are being called most and why i guess |
| 18:24:10 | evan | thats the best nevermind ever! |
| 18:24:24 | lypanov | ++ |
| 18:24:30 | evan | lypanov: ah, i think I see. |
| 18:24:45 | evan | you were compiling everything yes? |
| 18:24:53 | lypanov | evan: keep in mind that i brainstormed rubydium way more than i actually hacked on it |
| 18:25:00 | evan | heheh |
| 18:25:03 | lypanov | so out of every 1000 lines of crap |
| 18:25:04 | dgtized | and if you take into account real time, then MRI drops to like 5.5 seconds |
| 18:25:07 | lypanov | i had a neat idea |
| 18:25:19 | lypanov | um |
| 18:25:30 | lypanov | you could call it compiling yeah.. no. you really couldn't actually |
| 18:25:39 | evan | hah |
| 18:25:46 | lypanov | some day i should clean up the code so people actually understand it |
| 18:25:54 | evan | it was sort of trace based complication, yes? |
| 18:26:00 | lypanov | lol |
| 18:26:05 | lypanov | yes. trace based complication |
| 18:26:17 | rue | Oh, I meant to mention yesterday before I saw the stranger in the bathroom: we could use some slightly longer (but versatile) benchmarks |
| 18:26:24 | dbussink | dgtized: how are you running the bench? because for me ruby is faster than rbx without jit |
| 18:26:28 | rue | Also, morning |
| 18:26:31 | evan | rue: agreed |
| 18:26:35 | evan | rue: morning stranger! |
| 18:26:56 | rue | Even the full spec run does not seem to be able to fully shrug off the JIT cost |
| 18:27:04 | evan | yeah |
| 18:27:14 | evan | part of that is because almost all of the specs is blocks |
| 18:27:16 | dgtized | dbussink: ruby benchmark/rubinius/bm_array_each.rb ? |
| 18:27:19 | evan | and the JIT is ignoring blocks still |
| 18:27:26 | rue | Yep |
| 18:27:32 | lypanov | what are you jitting now? |
| 18:27:35 | dbussink | dgtized: yeah, doing that here too |
| 18:27:38 | rue | Oh, yes, the Prawn tests...lessee now |
| 18:27:40 | lypanov | user code or lib code or both? |
| 18:27:43 | evan | but still, you'd hope that it would make the kernel methods fast |
| 18:27:50 | evan | lypanov: whatever code is in the system |
| 18:28:01 | dgtized | dbussink: it's technically 1.8.7 I'm running I guess, so maybe they had a regression? |
| 18:28:13 | evan | lypanov: methods only atm, but it doesn't care where they come from |
| 18:28:14 | lypanov | can't you dump/load that at startup/shutdown? |
| 18:28:30 | dbussink | dgtized: me too, i can test with 1.8.6 too |
| 18:28:34 | lypanov | as in, cache the generated functions on disk |
| 18:28:49 | lypanov | did that with rubydium to great effect |
| 18:30:18 | lypanov | was going to use ast-md5's but never got around to it |
| 18:30:39 | dbussink | dgtized: these are my numbers: http://gist.github.com/123726 |
| 18:30:50 | evan | lypanov: i could |
| 18:31:07 | evan | lypanov: atm, the assembly contains some stuff specific to the current process |
| 18:31:12 | evan | so i'd have to weed that out. |
| 18:32:34 | evan | like using raw Symbols as arguments |
| 18:32:49 | dbussink | evan: do those numbers sound reasonable? |
| 18:32:51 | dgtized | dbussink: that's really strange: http://gist.github.com/123730 |
| 18:33:09 | evan | dbussink: run them again |
| 18:33:13 | evan | with TOTAL=5000 |
| 18:33:26 | evan | your numbers are too small to be trusted |
| 18:33:27 | lypanov | is there a way to make rake just do :debug by default so i don't forget? |
| 18:33:34 | evan | lypanov: nope |
| 18:33:44 | evan | why are you doing a debug build? |
| 18:33:52 | lypanov | cus it won't compile without it |
| 18:34:01 | brixen | lypanov: use gcc 4.0.1 |
| 18:34:16 | lypanov | i don't think i can. but i'll give it a try |
| 18:34:21 | brixen | lypanov: are you on os x? |
| 18:34:28 | lypanov | sorta :D |
| 18:34:32 | lypanov | better not to ask |
| 18:34:38 | lypanov | i'm on gentoo/osx |
| 18:34:40 | brixen | oh, you did that gentoo thing didn't ya |
| 18:34:43 | brixen | yeah |
| 18:34:46 | brixen | how's that working? |
| 18:34:51 | brixen | looks crazy |
| 18:35:03 | lypanov | zero issues since install |
| 18:35:04 | dbussink | evan: it really doesn't make a big difference actually |
| 18:35:07 | lypanov | and finally no need to sudo *ever* |
| 18:35:11 | dbussink | evan: numbers are in the same ballbark |
| 18:35:13 | lypanov | i frikking hate sudo'ing |
| 18:35:17 | brixen | lypanov: swee |
| 18:35:20 | brixen | er sweet |
| 18:35:28 | evan | dbussink: repaste them. |
| 18:35:32 | brixen | lypanov: you could also try 4.2.3 if it's available |
| 18:35:45 | dgtized | dbussink: ok, but we are definitely seeing completely different numbers -- x86 or x86_64? |
| 18:35:46 | dbussink | evan: updated the gist |
| 18:35:49 | lypanov | why would i not want debug build btw? |
| 18:35:56 | lypanov | i want to hack on rubinius not use it :) |
| 18:36:13 | evan | dbussink: ok, thats the numbers I get too |
| 18:36:18 | dbussink | dgtized: os x 10.5 |
| 18:36:19 | lypanov | debug is heavy debug? useless for benches? |
| 18:36:22 | evan | not sure why dgtized is seeing so awesome numbers |
| 18:36:34 | evan | lypanov: yes |
| 18:36:37 | evan | useless for benches |
| 18:36:38 | dbussink | dgtized: maybe a build with pthreads enabled on linux or something like that? |
| 18:36:42 | lypanov | teh lameness |
| 18:36:43 | brixen | lypanov: 4.3.[23] rather |
| 18:36:52 | lypanov | what d'all use when develling? |
| 18:36:59 | lypanov | inserts a y randomly |
| 18:37:02 | evan | lypanov: export CC=gcc-4.0 |
| 18:37:04 | evan | lypanov: then compile. |
| 18:37:17 | lypanov | oh but thats just far far too easy |
| 18:37:24 | evan | sorry |
| 18:37:27 | lypanov | :D |
| 18:37:28 | evan | i'll make shit more complicated next time. |
| 18:38:46 | lypanov | ah neat |
| 18:38:54 | lypanov | gentoo apparently has a funky gcc-config thingy |
| 18:39:04 | evan | they all do |
| 18:39:05 | evan | :D |
| 18:39:14 | evan | oh wait |
| 18:39:17 | evan | OS X doesn't |
| 18:39:19 | evan | i guess just linux |
| 18:39:32 | lypanov | osx has gcc_select though or whatever its called |
| 18:40:13 | evan | yeah, anyway. |
| 18:40:26 | lypanov | to reask. is there any reason i should ever need :debug? |
| 18:40:45 | evan | to debug the VM |
| 18:40:51 | evan | thats what I use it for |
| 18:41:06 | lypanov | k. then i'll probably need it quite a bit as i'm hoping to badly fuck up the vm soon |
| 18:41:07 | brixen | lypanov: it compiles without opts so you can actually follow the code in gdb |
| 18:41:24 | lypanov | ah, i'm more of a printf sorta guy |
| 18:41:32 | brixen | nooo :P |
| 18:41:43 | lypanov | is like totally old school and stuff |
| 18:41:51 | brixen | gangsta |
| 18:42:42 | evan | so, i'm working on making |
| 18:42:50 | evan | Type.coerce_to idx, Fixnum, :to_int |
| 18:42:51 | evan | faster |
| 18:42:58 | evan | using an AST transform in the compiler |
| 18:43:09 | lypanov | do you have cute backtraces that traces through the generated x86 up through the vm btw? |
| 18:43:12 | brixen | lypanov: http://tinyurl.com/art-of-debugging learn it, live it, love it |
| 18:43:23 | evan | lypanov: sorta |
| 18:43:29 | lypanov | i love ddd. don't get me wrong |
| 18:43:31 | lypanov | just hate gdb |
| 18:43:36 | lypanov | think its useless frankly |
| 18:43:54 | lypanov | data debugging is far more useful than flow debugging |
| 18:44:05 | lypanov | lack of go-back-in-time power is a killer for debugging |
| 18:44:11 | evan | yeah |
| 18:44:12 | evan | agreed. |
| 18:44:18 | evan | have you seen the reversible debuggers? |
| 18:44:19 | lypanov | java is far better than this c shit anyway |
| 18:44:29 | evan | there is some crazy patch to gdb |
| 18:44:32 | evan | that lets you go back in time. |
| 18:44:36 | evan | no really |
| 18:44:45 | lypanov | read about it. pretty neat tech |
| 18:45:10 | dgtized | evan: is this Type.coerce_to going to optimize for more then Fixnum? |
| 18:45:12 | evan | http://undo-software.com/undodb_man.html |
| 18:45:15 | evan | for those curious |
| 18:45:21 | evan | dgtized: we could make it do that |
| 18:45:32 | evan | just Fixnum at first |
| 18:45:35 | lypanov | some day you'll get to the stage when you don't have any c based stacktraces. then i'll be all happy |
| 18:46:41 | dgtized | I'm going to guess that Float, Symbol, and String Type.coercion optimizations would also be useful -- but that's purely unsubstantiated |
| 18:46:46 | lypanov | as in, turtles all the way down. 99% of the vm will be in ruby anyway and llvm will dynamically deoptimize on debugger attach |
| 18:47:24 | evan | lypanov: sounds great! |
| 18:48:40 | lypanov | wonders if evan has more detail on the q he posted in #jruby than most of the channel probably will |
| 18:48:58 | evan | hehe |
| 18:49:08 | evan | i've talked with headius about them |
| 18:49:15 | evan | i think he's still poking at it |
| 18:49:19 | evan | not sure about performance |
| 18:49:26 | lypanov | me too in detail a while back. just wondering if anything had happened since |
| 18:49:32 | lypanov | its not really about perf that i'm worrying |
| 18:49:39 | lypanov | no benches will show the improvement for the moment |
| 18:49:46 | lypanov | i worry more about theoritical perf improvement |
| 18:50:25 | lypanov | the java7 dyn invoke stuff is much like brixens equality saturation approach |
| 18:50:32 | lypanov | most likely it will bring amazing things |
| 18:50:39 | lypanov | but fuck, the engineers themselves have *no* idea why |
| 18:51:15 | evan | hehe |
| 18:51:28 | evan | the MethodHandle thing is cool |
| 18:51:35 | evan | i was thinking we could pretty easily add it to Rubinius |
| 18:51:40 | evan | but have to figure out how we'd use it first |
| 18:51:59 | lypanov | i stalled on rubydium because i started asking myself one big question: |
| 18:52:13 | lypanov | how could i add this opt, but in user level ruby code? |
| 18:52:25 | lypanov | never found the answer :D |
| 18:53:13 | evan | heh |
| 18:54:53 | lypanov | has anyone ever looked into which parts of rubinius perf might effect merb perf? |
| 18:57:02 | evan | a little, not too much yet |
| 19:02:14 | evan | so |
| 19:02:18 | evan | i was think |
| 19:02:23 | evan | maybe we should add another visibility |
| 19:02:33 | evan | call it system or something |
| 19:03:02 | evan | those methods wouldn't be reported by #methods, #instance_methods, etc |
| 19:03:13 | evan | so dynamic code that tries to remove methods wouldn't see them |
| 19:04:35 | brixen | hm, I like |
| 19:04:48 | brixen | how would you determine it though? |
| 19:04:50 | evan | we can then use them to build stuff |
| 19:04:57 | evan | determine which? |
| 19:05:00 | brixen | say, in the case we use Rubinius.privately for now? |
| 19:05:09 | brixen | or you only mean for remove_method? |
| 19:05:13 | brixen | undef |
| 19:05:52 | brixen | like, would it have normal call semantics? |
| 19:05:59 | evan | yeah |
| 19:06:07 | evan | they'd be callable like normal methods |
| 19:06:08 | brixen | when you say visibility, I think public vs private when calling |
| 19:06:12 | brixen | ok |
| 19:06:13 | evan | just excluded from lists |
| 19:06:22 | brixen | hm |
| 19:06:26 | brixen | so no reflection |
| 19:06:28 | brixen | ? |
| 19:06:30 | evan | well, i was thinking visibility, but it's more like tagging |
| 19:06:37 | evan | no, reflecting is fine |
| 19:06:50 | evan | maybe ala macruby, there is another argument to #methods |
| 19:06:55 | evan | that indicates if you want to see system methods |
| 19:06:59 | brixen | yeah |
| 19:07:01 | evan | or we add #system_methods |
| 19:07:11 | evan | rather than it being a visibility in the method_table |
| 19:07:18 | evan | it could be a tag on the CompiledMethod itself |
| 19:07:23 | dgtized | which methods are in that category? |
| 19:07:26 | evan | def blah |
| 19:07:27 | evan | 1 |
| 19:07:29 | evan | end.system! |
| 19:07:53 | evan | dgtized: well, i'm working on adding Object#__fixnum__ |
| 19:08:03 | evan | that returns true if the objcet is a Fixnum |
| 19:08:06 | evan | something like that |
| 19:09:11 | brixen | well, then the only thing it gives is protection from being undef'd? |
| 19:09:28 | evan | a couple things |
| 19:09:43 | evan | if it doesn't show up in #methods, then people won't automatically undef it, using builder style code |
| 19:09:48 | evan | or blankslate |
| 19:09:57 | brixen | ok |
| 19:10:04 | evan | plus, yes, undef could raise an exception if you try to undef one |
| 19:10:32 | brixen | I'd prefer system_method :foo rather than end.system! |
| 19:10:39 | evan | sure |
| 19:11:22 | brixen | so, these are tagged :system_method or whatever but are essentially public? |
| 19:11:29 | brixen | for visibility? |
| 19:11:42 | evan | hm. seems like it, yes. |
| 19:12:02 | evan | or they could be private and accessing using a special synta |
| 19:12:04 | evan | x |
| 19:12:08 | evan | perhaps something like |
| 19:12:15 | evan | System.__fixnum__ obj |
| 19:12:32 | evan | the compiler would flip that to call __fixnum__ as a private method on obj |
| 19:13:51 | brixen | hrm, I'm not a big fan of that syntax |
| 19:13:54 | evan | ok |
| 19:13:57 | brixen | if it's used in a lot of places |
| 19:14:10 | brixen | not sure it adds much over just being a public method |
| 19:14:20 | evan | sure |
| 19:14:31 | brixen | if redefines/undef's won't work, might as well be public |
| 19:14:39 | evan | so would we not allow system methods to be masked? |
| 19:14:53 | brixen | like redefined? |
| 19:15:02 | evan | class A < Object; def __fixnum__; true; end; end |
| 19:15:20 | brixen | maybe only in kernel mode, to allow for bootstrapping |
| 19:15:23 | brixen | but not in user code |
| 19:15:24 | evan | should that raise an error |
| 19:15:35 | evan | it's not a redefine |
| 19:15:46 | evan | but rather a subclass mask |
| 19:15:49 | brixen | right |
| 19:16:03 | brixen | hrm |
| 19:16:11 | evan | i'm thinking about these a bit in the context of the JIT |
| 19:16:27 | evan | primarily, the ability to have the JIT know about some system methods |
| 19:16:36 | evan | and emit custom code for them without guards |
| 19:16:41 | brixen | yeah |
| 19:16:51 | evan | because it can reason that __fixnum__ IS always what it thinks it is. |
| 19:17:19 | brixen | i guess we could start with them being open and if you (the user) breaks it, we could disallow that |
| 19:17:33 | brixen | if they are not normally visible... |
| 19:17:43 | brixen | I guess you'd still need to prevent accidental conflicts |
| 19:17:52 | evan | well |
| 19:17:57 | evan | if the JIT speculates |
| 19:18:04 | evan | then their overriden version may never be called. |
| 19:18:14 | evan | oh oh |
| 19:18:16 | evan | actually |
| 19:18:17 | evan | nm. |
| 19:18:23 | evan | we can let them override them. |
| 19:18:38 | evan | just realized that the JIT can just look at the SendSite cache to know which version was used |
| 19:19:01 | evan | i guess, for that matter, we could all them to undef and such if they really want |
| 19:20:41 | brixen | makes sense |
| 19:25:18 | evan | hm, this Type.coerce_to rewrite is just making shit slower... |
| 19:25:19 | evan | :/ |
| 19:27:38 | evan | uumm |
| 19:27:41 | evan | wtf did I do... |
| 19:27:55 | rue | Unfucking argument processing in core from MRI conventions (all 8 of them) would probably be a much higher yield |
| 19:28:15 | evan | eh? |
| 19:28:21 | evan | which argument processing do ya mean? |
| 19:29:01 | rue | The reason Type.coerce_to exists to begin with |
| 19:29:37 | evan | hm, so what do we use instead? |
| 19:30:26 | rue | Well, we cannot really break compatibility there, I think |
| 19:30:32 | ddub | could you just make certain operations really inefficient? |
| 19:30:58 | ddub | like say, remove_const could result in all cached code being flushed (in the absense of a way of telling which particular methods are using said constant) |
| 19:31:04 | evan | rue: i'm not sure what ya mean by unfucking argument processing |
| 19:31:34 | evan | therealadam: WELCOME TO THE THUNDERDOME |
| 19:31:52 | ddub | is there a fakeadam? |
| 19:32:36 | rue | Several |
| 19:32:57 | rue | evan: coerce_to does 2 kind_ofs and one send |
| 19:33:11 | lypanov | ddub: i agree with penalizing the stupid fucks that play with this sort of code |
| 19:33:17 | rue | Also, wtf #coerce_to_comparison evil |
| 19:33:32 | evan | did someone write that? |
| 19:33:51 | ddub | #coerce_to_evil |
| 19:33:55 | evan | sweet zeus |
| 19:33:56 | evan | wtf. |
| 19:34:15 | rue | That is not my favourite kind of core code :P |
| 19:34:19 | evan | rue: it's unused |
| 19:34:22 | evan | lets nuke it. |
| 19:34:34 | evan | before someone noticies |
| 19:35:10 | lypanov | k. gotta run |
| 19:35:11 | rue | ddub: Yes, I think it is OK to optimise for the common case (at the very least initially, with potential updates at $5 apiece) |
| 19:35:24 | evan | marcandre added it |
| 19:35:43 | rue | marcandre: Bad! |
| 19:35:52 | evan | it's pretty dumb. |
| 19:35:57 | rue | No cookie |
| 19:36:14 | marcandre | What have I done exactly? |
| 19:36:24 | evan | marcandre: Type.coerce_to_comparison |
| 19:36:27 | evan | whats the point of it |
| 19:36:33 | rue | evan: So, a sane implementation could just directly do the #to_whatever call instead of bothering with TWO #kind_of?s |
| 19:36:57 | marcandre | Isn't it to map -5 to -1, for example? |
| 19:37:08 | evan | you tell me |
| 19:37:08 | marcandre | needs a ram upgrade |
| 19:37:09 | evan | you wrote it |
| 19:37:58 | rue | Hrm |
| 19:38:50 | rue | There is *significant* perf degradation when I load the Prawn tests multiple times...I wonder if it is hitting the caches really badly or something |
| 19:39:10 | marcandre | Ok. So the idea is to raise an error if a comparison block/method returns nil. |
| 19:39:28 | rue | Essentially, 1x run is ~2m, 2x is ~5m, 3x is ~10m |
| 19:39:45 | evan | rue: werid. |
| 19:40:02 | marcandre | The checking for <=> 0 was just to mimick MRI, but it's not really needed here, since the result is then compared with 0 again. |
| 19:40:03 | ddub | sounds like really you shouldn't be looking at prawn |
| 19:40:23 | rue | ddub: ? |
| 19:40:42 | rue | Hee, Brain Ford :) |
| 19:40:45 | ddub | sorry, a little bit of prawnographic humor |
| 19:41:14 | rue | Oh, oh, I see...it is that thing with humans and their appendages.. |
| 19:41:15 | evan | marcandre: you mean for nil, yes? |
| 19:42:08 | brixen | rue: he could have just gone all the way with Brain Food :) |
| 19:42:09 | marcandre | I mean raising if nil, but the different returns with tests for > 0, <0 could go. |
| 19:43:25 | evan | marcandre: hm, ok, i see... |
| 19:43:49 | marcandre | What exactly is the problem with it? |
| 19:43:50 | evan | it still seems weird. |
| 19:44:19 | evan | why is this not |
| 19:44:23 | evan | raise .... |
| 19:44:26 | evan | return cmp |
| 19:44:57 | marcandre | It is now :-) |
| 19:44:58 | boyscout | More efficient coerce_to_comparison - ba27148 - Marc-Andre Lafortune |
| 19:45:19 | evan | macournoyer: so you only use this in enumerable |
| 19:45:26 | evan | why not make it a private helper method |
| 19:45:32 | evan | it would be faster to call that way |
| 19:47:29 | marcandre | evan: I'd be surprised if other places in the code wouldn't need it. Let me check |
| 19:47:46 | evan | marcandre: most things don't care about checking the result of <=> |
| 19:47:51 | evan | they just compare and let it blow up |
| 19:48:05 | evan | thats faster too |
| 19:48:17 | marcandre | btw, macournoyer is the famous Marc-André Cournoyer (also from Montreal). I'm Marc-André Lafortune |
| 19:48:38 | evan | yes, we know :D |
| 19:48:45 | evan | we're happy to have to marc-andre's |
| 19:48:49 | evan | two |
| 19:48:55 | macournoyer | ya! |
| 19:49:12 | marcandre | evan: you don't get the right error, though... NoMethodError on nil vs "can't compare a & b" |
| 19:49:15 | macournoyer | and my parents thought they gave me a unique name... |
| 19:49:25 | marcandre | yeah, mine too ;-) |
| 19:49:26 | evan | marcandre: so wrap that in a begin/rescue |
| 19:49:48 | evan | thats sort of like being named Evan |
| 19:49:50 | evan | i don't run into too many |
| 19:49:56 | evan | all though there are a ton in the ruby community |
| 19:50:04 | evan | like at least 5! |
| 19:50:09 | macournoyer | yes, a lot |
| 19:51:40 | marcandre | evan: begin/rescue is cute, but what if the block calls "nil > 0"? Then we're _supposed_ to raise a NoMethodError... |
| 19:52:16 | evan | stupid MRI |
| 19:52:18 | evan | GAH |
| 19:52:20 | rue | evan: ^^ The argument processing I was referring to :P |
| 19:54:09 | rue | Actually, not using coerce_to would remove three, not two method calls |
| 19:55:59 | evan | ie, just call the method |
| 19:56:02 | evan | to_i or whatever |
| 19:56:18 | marcandre | if you need it, what could be done is putting a "|| raise ..." after all comparisons |
| 19:56:34 | evan | FUCK no. |
| 19:56:38 | marcandre | lol |
| 19:56:41 | evan | thats disgusting. |
| 19:56:56 | brixen | || die ... it's very perlish |
| 19:57:16 | marcandre | as for putting it private in Enumerable: it doesn't belong there! |
| 19:57:50 | marcandre | moreover, I just double checked that Array#sort doesn't raise the right error if arguments can't be compared... |
| 19:58:32 | marcandre | Now you can decide "fuck the specs, let the comparison fail on nil > 0", but to be 100% compliant, I think coerce_to_comparison is needed |
| 19:59:07 | brixen | option 2: get MRI to be consistent about the errors |
| 19:59:12 | brixen | long shot, I know, but... |
| 19:59:43 | marcandre | Why do you guys think MRI is not consistent? |
| 19:59:51 | evan | or, rather that Type.coerce_to |
| 19:59:51 | rue | Because it is not? :) |
| 19:59:55 | evan | why not go the smalltalk route |
| 20:00:16 | evan | devise a small number of methods make up the protocol |
| 20:00:22 | marcandre | rue: yeah, I realize that there are still many inconsistencies around :-) |
| 20:00:27 | evan | and distribute them around the hierarchy for desired effect |
| 20:00:27 | marcandre | but in this case? |
| 20:00:33 | evan | in the case of Type.coerce for Fixnum |
| 20:00:46 | evan | class Fixnum; def __to_fixnum__; self; end; |
| 20:01:02 | evan | class Object; def __to_fixnum__; Type.coerce_to self, Fixnum, :to_int; end; end |
| 20:01:09 | evan | then you call __to_fixnum__ |
| 20:01:22 | evan | where you NEED a fixnum |
| 20:01:44 | evan | again, this is a good usecase for system methods |
| 20:01:48 | evan | __to_fixnum__ being such. |
| 20:01:55 | rue | Meh, I would just let it fail :) |
| 20:03:13 | brixen | marcandre: I'm talking about nil > 0 raising a NME |
| 20:04:02 | marcandre | brixen: MRI doesn't raise a NME, rbx does |
| 20:04:45 | brixen | marcandre: yes MRI does on nil > 0 |
| 20:04:53 | marcandre | I mean things like the current Array#sort do. |
| 20:05:20 | marcandre | Oh yes. You'd rather have a "can't compare nil with 0"? |
| 20:06:04 | brixen | marcandre: there are just a lot of places coercion is handled in MRI and not always consistently |
| 20:07:02 | marcandre | But in the case of methods needing to compare x and y, if x <=> y returns nil it's ok to raise an ArgumentError instead of a NME on nil, no? |
| 20:08:52 | brixen | the fact that nil <=> 0 != 0 <=> nil is ugh |
| 20:09:34 | marcandre | oh. yes. I see. |
| 20:11:15 | marcandre | I didn't realize that. You're right |
| 20:11:30 | marcandre | If nil <=> 0 returned nil, that would be much nicer I think. |
| 20:12:19 | brixen | marcandre: you've looked through MRI source: rb_Integer, rb_to_int, rb_check_to_integer, rb_to_integer, rb_check_convert_type, rb_convert_type, convert_type, rb_f_integer ? |
| 20:12:21 | marcandre | And not having the coerce_to_comparison call would generate the right class of exception (albeit without the informative message) |
| 20:12:51 | marcandre | I try to avoid it ;-) |
| 20:13:21 | brixen | well, it's very complex how all those are used throughout the code |
| 20:13:33 | brixen | that's partly what I mean by consistency |
| 20:13:47 | brixen | MRI is so complex in this area, oddities are sure to surface |
| 20:15:33 | brixen | I think that <=> should either always return { nil, -1, 0, 1 } or have a NotComparableError exception and return { -1, 0, 1 } |
| 20:15:59 | marcandre | I'd vote for that too... |
| 20:16:02 | brixen | but should never raise NME |
| 20:16:21 | marcandre | As there been discussion on ruby-core about having an Object#<=> defined? |
| 20:16:31 | brixen | not sure |
| 20:17:21 | rue | Even converting a NoMethodError to TypeError would still save two method calls |
| 20:18:27 | brixen | right, ArgumentError masquerading as a TypeError is another inconsistency |
| 20:18:41 | brixen | it'd be nice to query rubyspec for these cases |
| 20:19:50 | marcandre | If you don't mind the less informative error, instead of coerce_to_comparison(a, b, block.call(a,b)) < 0 we could use 0> block.call(a,b) |
| 20:20:07 | marcandre | This would throw an ArgumentError if it returns nil. |
| 20:20:54 | marcandre | Only the message would be less informative "comparison of Fixnum with nil failed" instead of "comparison of a.class with b.class failed" |
| 20:22:30 | therealadam | evan: ahoy (belated) |
| 20:23:49 | evan | avast |
| 20:24:25 | brixen | marcandre: I wonder if it'd be too hard to get a rational protocol for all relational operators |
| 20:24:56 | brixen | marcandre: based on a NotComparableError exception ond { true, false } or { -1, 0, 1 } |
| 20:25:15 | brixen | to hard to convince MRI* |
| 20:25:27 | marcandre | brixen: personally, I like the fact that <=> returns nil |
| 20:25:47 | brixen | well, there's just no accounting for taste... :P |
| 20:26:26 | marcandre | But it should be symetrical, at least. It would be easy to implement: use recursion guards and reverse the arguments. Return nil if recursion detected. |
| 20:26:56 | marcandre | The thing is, you can't change the semantics of <=>. |
| 20:27:22 | marcandre | You could define another operator, that would call <=> || raise NotComparableError |
| 20:27:57 | marcandre | But unless it's something like __compare__ there would be too much change of a conflict. |
| 20:30:15 | brixen | marcandre: I dunno, NilClass is not a Comparable, so 0 <=> nil => nil is just madness IMO |
| 20:30:26 | brixen | but I need food... bbiab... |
| 20:31:05 | marcandre | But nil == 0 # => false, nil != 0 # => true, exactly like a == b and a != b if a <=> b returns nil |
| 20:33:02 | rue | Aaaaargh |
| 20:33:13 | rue | I think we should paste this conversation to ruby-core :/ |
| 20:34:48 | marcandre | I'll be glad to post a feature request on redmine, especially if we can present it well |
| 20:36:33 | brixen | munches pizza |
| 20:37:37 | brixen | marcandre: it is true that #== and #!= are equality relations distinct from what I consider comparable (partial-ordering) relations like #<=> #< #> etc |
| 20:38:17 | brixen | marcandre: but either all comparable relations should return nil for "not comparable" or they all should raise |
| 20:38:41 | brixen | the inconsistency between 0 <=> nil and 0 < nil sucks |
| 20:38:51 | marcandre | Hmmm. The thing is: if x and y are not comparable... then they are not equal, right? |
| 20:39:01 | brixen | no, not in my view |
| 20:39:19 | brixen | because equality can be based on identity or equal value |
| 20:39:30 | marcandre | So if x <=> y returns nil (or raises a NotComparableError), I still would like x == y to return false |
| 20:39:38 | brixen | which has no connotation of comparable, in the sense of a partial order |
| 20:40:16 | brixen | yes, #== is in a distinct class of operators from #<=> IMO |
| 20:41:46 | marcandre | In some ways, yes. But you're adding weight to the current position of MRI... |
| 20:42:21 | brixen | mm, no |
| 20:42:40 | brixen | in my scheme, 0 <=> nil and 0 < nil behave consistently |
| 20:42:50 | brixen | 0 == nil => false |
| 20:43:08 | brixen | equality is something you can define between *any* a and b |
| 20:43:19 | marcandre | You mean nil <=> 0, because 0 <=> nil is already nil |
| 20:43:26 | brixen | either based on identity or equal value, with coercion semantics for value comparison |
| 20:44:09 | brixen | no, I mean http://gist.github.com/123802 |
| 20:45:10 | marcandre | Funny, I don't see that as being inconsistent. |
| 20:45:26 | marcandre | There are cases where two objects are different but no order exist between them. |
| 20:46:13 | marcandre | In that case, it is informative to answer that they are different (i.e. <=> returns nil) but asking < can not return a meaningful value so it raises an error |
| 20:46:29 | brixen | how is that consistent? |
| 20:46:37 | brixen | neither op can return an answer |
| 20:46:57 | marcandre | well, nil means that they can't be compared, as per definition of <=> |
| 20:47:16 | brixen | and nil could mean they can't be compared according to #< |
| 20:47:43 | marcandre | Yeah, except that you'd have to rewrite all the code! |
| 20:48:01 | marcandre | unless a < b ==> if a < b == false |
| 20:49:23 | brixen | yes, I think they should both raise, not return nil |
| 20:50:00 | marcandre | Ok. But then you want everyone that ever defined a <=> method on their classes to rewrite it... |
| 20:50:47 | boyscout | Remove cruft - 2ba827a - Evan Phoenix |
| 20:50:47 | boyscout | Speed up a basic form of Type.coerce_to - 52879f7 - Evan Phoenix |
| 20:50:47 | brixen | I suppose... |
| 20:51:35 | marcandre | I think a lofty goal would be to have Ruby be at least symetrical with respect to it's comparison operators. |
| 20:52:02 | brixen | well, might as well add consistent to that lofty goal :) |
| 20:52:19 | brixen | it'll probably break some code no matter what you do |
| 20:53:01 | marcandre | Well, I think it would break code that would compare apples and oranges and rely on the error being throw to be of type NoMethodError... |
| 20:53:16 | brixen | marcandre: exactly |
| 20:53:20 | brixen | how crazy is that |
| 20:53:47 | brixen | what's NME got to do with comparability? |
| 20:53:55 | marcandre | It would be crazy to do that, so I'd have no pity for those cases |
| 20:54:28 | marcandre | The more I think about it, the more I believe there should be an <=> operator defined by default. |
| 20:54:52 | marcandre | I think another argument is that some methods of Enumerable rely on <=>, and that's the only operator they have to rely on. |
| 20:55:26 | brixen | sounds like you see 3 classes of comparison: equality, comparability (#<=>), and relational (#<, etc) |
| 20:55:32 | marcandre | It would make Enumerable even more pure than it is right now. |
| 20:55:53 | marcandre | I see the <=> as asking all the questions at the same time, for efficiency. |
| 20:56:27 | brixen | then #<=> must behave like any other relation operator to pass my def of consistency |
| 20:56:29 | marcandre | I.e. "tell me if these guys are the same or different, and if different, can you order them"? |
| 20:56:42 | brixen | heh |
| 20:56:44 | evan | who ever keeps writing "if(" |
| 20:56:45 | evan | STOP IT. |
| 20:56:49 | evan | in ruby |
| 20:57:06 | brixen | marcandre: you're bact to 3 classes of op |
| 20:57:09 | brixen | er back |
| 20:58:11 | marcandre | Not sure what you mean by classes, but I see two: one that requires an order (otherwise raises an ArgumentError) and one that doesn't. |
| 20:59:03 | brixen | marcandre: well a <=> x => 0 ==> a == x |
| 20:59:12 | brixen | so <=> subsumes == |
| 20:59:24 | marcandre | checks the definition for subsumes |
| 20:59:50 | brixen | returning -1 or 1 ==> a, b can be ordered |
| 21:00:05 | marcandre | can be ordered and are different, yes |
| 21:00:08 | brixen | so the only other possibility is that a, b are not comparable at all |
| 21:00:58 | brixen | I'm having trouble seeing the value of <=> having a different result that < for the case where you cannot compare at all |
| 21:01:02 | marcandre | Well, they could be semi-ordered, so they are comparable in that they can sometimes be ordered but not always. |
| 21:01:14 | brixen | example? |
| 21:01:18 | marcandre | graphs |
| 21:01:54 | marcandre | I can't draw here, but some graphs are subgraphs of others (<) but that's not always the case. |
| 21:02:07 | marcandre | *---* < *---*---* |
| 21:02:26 | marcandre | *---* < Triangle |
| 21:02:36 | brixen | hmm |
| 21:02:36 | marcandre | Triangle <=> Square # ==> nil |
| 21:05:52 | brixen | sorry, back.. |
| 21:05:55 | marcandre | http://en.wikipedia.org/wiki/Partially_ordered_set |
| 21:06:17 | brixen | yeah |
| 21:06:42 | brixen | so, a < b ==> a <=> b => a value |
| 21:07:12 | brixen | there is no case in which a <=> b => nil that a < b is defined |
| 21:07:16 | brixen | and vice versa |
| 21:07:26 | marcandre | No, indeed. |
| 21:07:30 | brixen | so, why have different results? |
| 21:08:05 | marcandre | When do you have different results? |
| 21:08:26 | brixen | well, a < b raises and a <=> b => nil |
| 21:08:44 | brixen | essentiall, you want to say: if a <=> b then x else y end |
| 21:08:54 | brixen | I guess that's reason enough |
| 21:09:22 | marcandre | Yeah. Basically I think it's quite useful to return nil in that case |
| 21:09:46 | marcandre | <=> doesn't _assume_ they are ordered, while < does. |
| 21:10:14 | marcandre | And the fact that < returns false, there's no way you'd want to return nil and false with a different meaning. |
| 21:10:34 | brixen | indeed |
| 21:10:44 | marcandre | But really, I think the point is moot. Changing the semantics of <=> is next to impossible, I believe |
| 21:11:14 | brixen | ok, I'll settle for symmetric |
| 21:11:16 | brixen | :) |
| 21:11:19 | marcandre | The only hope for some symmetry and consistency is to have a <=> defined for all objects, in the same that == and != are defined |
| 21:11:30 | boyscout | Style cleanup - 37fe0d3 - Evan Phoenix |
| 21:11:40 | brixen | but I still think raising if objects are not comparable is a valid solution |
| 21:12:25 | brixen | yeah, I agree, #<=> should be defined everywhere |
| 21:13:59 | marcandre | How about this: I'll write something up to propose adding <=> everywhere, and if it passes, I'll let you write something to propose it raises an error ;-) |
| 21:14:39 | brixen | nah, you've convinced me :) |
| 21:15:06 | brixen | it's actually very convenient to have a value that signifies undefined for computation |
| 21:15:18 | brixen | and one you can use as a boolean noless |
| 21:16:43 | marcandre | I've got to prepare for game night, but I'll write something up and email it later tonight or tomorrow, and I'll cc rue and evan so anyone can pitch in for suggestions |
| 21:16:55 | brixen | sweet |
| 22:12:58 | rue | Oh wtf. MTpro seems to allow <script /> in blog posts by default :/ |