Re: Large core.math expression produces excessively long Clojure-generated class names
FWIW: I tried to reproduce it here: https://github.com/lvh/nestedrepro but I was unable to cause these sorts of errors using try/catch and do. On Sat, Oct 6, 2018 at 6:17 PM Laurens Van Houtven <_...@lvh.io> wrote: > I'm hitting CLJ-1852 [0] (Clojure-generated class names length exceed > file-system limit) with a large core.match expression. I have verified that > it is the number of clauses in core.match: compilation works as soon as I > reduce it, and looking at `target/` it is actually producing very long > filenames a la: > > > 'iddqd$xyzzy$fn__19779$fn__19788$fn__19789$fn__19790$fn__19793$fn__19794$fn__19795$fn__19796$fn__19797$fn__19814$fn__19815$fn__19816$fn__19819$fn__19820$fn__19823$fn__19824$fn__19825$fn__19826.class' > > However, I don't quite understand _why_ core.match produces such long > filenames. The error and filename suggest the problem is deeply nested > fn*s. Judging by macroexpand-all it's just a ton of let and try/catch which > I'd expect don't compile to fn*s internally (I'm aware of the equivalent > between let and lambda but I expect that's not really how it's > implemented). I am trying to understand why it's producing all of these > nested fns as compiled classes to see if I can somehow work around this > (without rewriting the function completely, hopefully!). > > I've found a similar reproducer here[1]. Unfortunately it doesn't do a > better job explaining _why_ the compiler emits that. Any tools for helping > me understand the compiler would be helpful. I'm already quite comfortable > with JVM bytecode and asm. Is the best way to figure this out just to read > Compiler.java? > > > [0]: https://dev.clojure.org/jira/browse/CLJ-1852 > [1]: https://github.com/simonpure/clojure-match-io-exception > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Large core.math expression produces excessively long Clojure-generated class names
I was able to fork your repo and created a different 'growing expression' that nests each one inside the 'catch' clause of the enclosing try expression, which is what the macro-expansion of core.match `match` expressions do as they get longer. It shows that the longest class file names are getting longer. I believe that at least the body of the catch clause is enclosed in a new function by the Clojure compiler, if not the main body of the try. https://github.com/jafingerhut/nestedrepro Andy On Sun, Oct 7, 2018 at 8:36 AM Laurens Van Houtven <_...@lvh.io> wrote: > FWIW: I tried to reproduce it here: https://github.com/lvh/nestedrepro > but I was unable to cause these sorts of errors using try/catch and do. > > On Sat, Oct 6, 2018 at 6:17 PM Laurens Van Houtven <_...@lvh.io> wrote: > >> I'm hitting CLJ-1852 [0] (Clojure-generated class names length exceed >> file-system limit) with a large core.match expression. I have verified that >> it is the number of clauses in core.match: compilation works as soon as I >> reduce it, and looking at `target/` it is actually producing very long >> filenames a la: >> >> >> 'iddqd$xyzzy$fn__19779$fn__19788$fn__19789$fn__19790$fn__19793$fn__19794$fn__19795$fn__19796$fn__19797$fn__19814$fn__19815$fn__19816$fn__19819$fn__19820$fn__19823$fn__19824$fn__19825$fn__19826.class' >> >> However, I don't quite understand _why_ core.match produces such long >> filenames. The error and filename suggest the problem is deeply nested >> fn*s. Judging by macroexpand-all it's just a ton of let and try/catch which >> I'd expect don't compile to fn*s internally (I'm aware of the equivalent >> between let and lambda but I expect that's not really how it's >> implemented). I am trying to understand why it's producing all of these >> nested fns as compiled classes to see if I can somehow work around this >> (without rewriting the function completely, hopefully!). >> >> I've found a similar reproducer here[1]. Unfortunately it doesn't do a >> better job explaining _why_ the compiler emits that. Any tools for helping >> me understand the compiler would be helpful. I'm already quite comfortable >> with JVM bytecode and asm. Is the best way to figure this out just to read >> Compiler.java? >> >> >> [0]: https://dev.clojure.org/jira/browse/CLJ-1852 >> [1]: https://github.com/simonpure/clojure-match-io-exception >> >> -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Large core.math expression produces excessively long Clojure-generated class names
Laurens: I know on Clojurians Slack you pointed out this repository: https://github.com/simonpure/clojure-match-io-exception This is not really an issue on a file system that can have very long file names. My recommendation is if you can arrange that, you should be good to go. There is a 'quick workaround' section in the README of the repository above showing one way to do that on a Linux machine, if your base Linux kernel imposes file name length limitations that are being exceeded (apparently some encrypted Linux file systems have such limits). I haven't seen the file system name issue on a Mac OS X system. I haven't tried Windows to know what its file name length limitations might be, or whether there are similar workarounds to enable longer file names. There are a couple of relevant Clojure JIRA tickets I know of, which anyone is welcome to vote on, but waiting for them to be resolved before deciding what you are going to do about this issue doesn't seem like a viable approach. Kevin Downey has worked on patches for the Clojure ticket https://dev.clojure.org/jira/browse/CLJ-701 that change the Clojure compiler so that instead of wrapping various things in (fn* ...) that the compiler does today, instead creates separate methods for those things. I don't know how production-worthy any of them are, but the comments seem to imply that there are non-working edge cases for those approaches at the moment. You can vote on that issue https://dev.clojure.org/jira/browse/CLJ-1852 comments mention some ideas of changing the Clojure compiler to use shorter class file names, e.g. via hashing the contents of long names to shorter ones. Andy On Sun, Oct 7, 2018 at 10:42 AM Andy Fingerhut wrote: > I was able to fork your repo and created a different 'growing expression' > that nests each one inside the 'catch' clause of the enclosing try > expression, which is what the macro-expansion of core.match `match` > expressions do as they get longer. > > It shows that the longest class file names are getting longer. I believe > that at least the body of the catch clause is enclosed in a new function by > the Clojure compiler, if not the main body of the try. > > https://github.com/jafingerhut/nestedrepro > > Andy > > > On Sun, Oct 7, 2018 at 8:36 AM Laurens Van Houtven <_...@lvh.io> wrote: > >> FWIW: I tried to reproduce it here: https://github.com/lvh/nestedrepro >> but I was unable to cause these sorts of errors using try/catch and do. >> >> On Sat, Oct 6, 2018 at 6:17 PM Laurens Van Houtven <_...@lvh.io> wrote: >> >>> I'm hitting CLJ-1852 [0] (Clojure-generated class names length exceed >>> file-system limit) with a large core.match expression. I have verified that >>> it is the number of clauses in core.match: compilation works as soon as I >>> reduce it, and looking at `target/` it is actually producing very long >>> filenames a la: >>> >>> >>> 'iddqd$xyzzy$fn__19779$fn__19788$fn__19789$fn__19790$fn__19793$fn__19794$fn__19795$fn__19796$fn__19797$fn__19814$fn__19815$fn__19816$fn__19819$fn__19820$fn__19823$fn__19824$fn__19825$fn__19826.class' >>> >>> However, I don't quite understand _why_ core.match produces such long >>> filenames. The error and filename suggest the problem is deeply nested >>> fn*s. Judging by macroexpand-all it's just a ton of let and try/catch which >>> I'd expect don't compile to fn*s internally (I'm aware of the equivalent >>> between let and lambda but I expect that's not really how it's >>> implemented). I am trying to understand why it's producing all of these >>> nested fns as compiled classes to see if I can somehow work around this >>> (without rewriting the function completely, hopefully!). >>> >>> I've found a similar reproducer here[1]. Unfortunately it doesn't do a >>> better job explaining _why_ the compiler emits that. Any tools for helping >>> me understand the compiler would be helpful. I'm already quite comfortable >>> with JVM bytecode and asm. Is the best way to figure this out just to read >>> Compiler.java? >>> >>> >>> [0]: https://dev.clojure.org/jira/browse/CLJ-1852 >>> [1]: https://github.com/simonpure/clojure-match-io-exception >>> >>> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegroups.com >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post t
Re: Large core.math expression produces excessively long Clojure-generated class names
I saw that workaround, but I’m hitting the much harder 255 ext4 (and every other major Linux filesystem) limit than the limit ecryptfs introduces by layering on top of other filesystems. It’s a big match statement :-) A lot of the match clauses could be case clauses. They’re just not because one style of matching is better than two, and it’s annoying to rewrite code just because I figured out too late that I actually need a core.match feature. I might end up writing that other match macro :) Thanks for the reproducer! That was very insight-producing. lvh Sent from my iPhone > On Oct 7, 2018, at 13:11, Andy Fingerhut wrote: > > Laurens: I know on Clojurians Slack you pointed out this repository: > https://github.com/simonpure/clojure-match-io-exception > > This is not really an issue on a file system that can have very long file > names. My recommendation is if you can arrange that, you should be good to > go. There is a 'quick workaround' section in the README of the repository > above showing one way to do that on a Linux machine, if your base Linux > kernel imposes file name length limitations that are being exceeded > (apparently some encrypted Linux file systems have such limits). I haven't > seen the file system name issue on a Mac OS X system. I haven't tried > Windows to know what its file name length limitations might be, or whether > there are similar workarounds to enable longer file names. > > There are a couple of relevant Clojure JIRA tickets I know of, which anyone > is welcome to vote on, but waiting for them to be resolved before deciding > what you are going to do about this issue doesn't seem like a viable approach. > > Kevin Downey has worked on patches for the Clojure ticket > https://dev.clojure.org/jira/browse/CLJ-701 that change the Clojure compiler > so that instead of wrapping various things in (fn* ...) that the compiler > does today, instead creates separate methods for those things. I don't know > how production-worthy any of them are, but the comments seem to imply that > there are non-working edge cases for those approaches at the moment. You can > vote on that issue > > https://dev.clojure.org/jira/browse/CLJ-1852 comments mention some ideas of > changing the Clojure compiler to use shorter class file names, e.g. via > hashing the contents of long names to shorter ones. > > Andy > > >> On Sun, Oct 7, 2018 at 10:42 AM Andy Fingerhut >> wrote: >> I was able to fork your repo and created a different 'growing expression' >> that nests each one inside the 'catch' clause of the enclosing try >> expression, which is what the macro-expansion of core.match `match` >> expressions do as they get longer. >> >> It shows that the longest class file names are getting longer. I believe >> that at least the body of the catch clause is enclosed in a new function by >> the Clojure compiler, if not the main body of the try. >> >> https://github.com/jafingerhut/nestedrepro >> >> Andy >> >> >>> On Sun, Oct 7, 2018 at 8:36 AM Laurens Van Houtven <_...@lvh.io> wrote: >>> FWIW: I tried to reproduce it here: https://github.com/lvh/nestedrepro >>> but I was unable to cause these sorts of errors using try/catch and do. >>> On Sat, Oct 6, 2018 at 6:17 PM Laurens Van Houtven <_...@lvh.io> wrote: I'm hitting CLJ-1852 [0] (Clojure-generated class names length exceed file-system limit) with a large core.match expression. I have verified that it is the number of clauses in core.match: compilation works as soon as I reduce it, and looking at `target/` it is actually producing very long filenames a la: 'iddqd$xyzzy$fn__19779$fn__19788$fn__19789$fn__19790$fn__19793$fn__19794$fn__19795$fn__19796$fn__19797$fn__19814$fn__19815$fn__19816$fn__19819$fn__19820$fn__19823$fn__19824$fn__19825$fn__19826.class' However, I don't quite understand _why_ core.match produces such long filenames. The error and filename suggest the problem is deeply nested fn*s. Judging by macroexpand-all it's just a ton of let and try/catch which I'd expect don't compile to fn*s internally (I'm aware of the equivalent between let and lambda but I expect that's not really how it's implemented). I am trying to understand why it's producing all of these nested fns as compiled classes to see if I can somehow work around this (without rewriting the function completely, hopefully!). I've found a similar reproducer here[1]. Unfortunately it doesn't do a better job explaining _why_ the compiler emits that. Any tools for helping me understand the compiler would be helpful. I'm already quite comfortable with JVM bytecode and asm. Is the best way to figure this out just to read Compiler.java? [0]: https://dev.clojure.org/jira/browse/CLJ-1852 [1]: https://github.com/simonpure/clojure-match-io-exception >>> >>> -- >>> You received this mess
Re: metric-based testing (evaluating changes to Monte Carlo tree search library)
I ended up writing a new metric-test function for this problem, which I will likely release as a library soon. For now, the function is just embedded in the project where I first needed it. Usage looks like the following. Note that the baseline argument is optional. If the baseline argument is not present, then the test will fail and will recommend a starting value for baseline. (ns figurer.car-example-test (:require [clojure.test :refer :all] [figurer.car-example :refer :all] [figurer.core :as figurer] [metric-test.core :refer [metric-test]])) (def metrics {:expected-value figurer/expected-value :plan-value (fn [solution] (let [plan (figurer/sample-plan solution) plan-value (/ (apply + (map (:value solution) (:states plan) )) (count (:states plan)))] plan-value))}) (deftest gentle-turn-metric-test (metric-test "gentle turn metric 0.1" #(figurer/figure gentle-turn-problem {:max-seconds 0.1}) :metrics metrics :baseline {:expected-value {:mean 62.508, :stdev 0.542} :plan-value {:mean 70.569, :stdev 1.46}})) And output for a failing test looks like this: FAIL in (gentle-turn-metric-test) (core.clj:112) gentle turn metric 0.1 Some metrics changed significantly compared to the baseline. | Metric |Old |New |Change | Unusual | |-+++---+-| | :expected-value | 62.508 ± 0.542 | 72.566 ± 0.499 | 10.058 (18.558 stdev) | * | | :plan-value | 70.569 ± 1.46 | 70.541 ± 1.378 | -0.028 (-0.019 stdev) | | New baseline if these changes are accepted: {:expected-value {:mean 72.566, :stdev 0.499}, :plan-value {:mean 70.541, :stdev 1.378}} expected: false actual: false Here is the commit in which I created the metric-test function and used it for just one of my tests: https://github.com/ericlavigne/figurer/commit/1153b5d4db898d042de6e3aa0ab9d77e65c6e3cc On Saturday, October 6, 2018 at 5:41:27 PM UTC-4, Eric Lavigne wrote: > > *Summary* > > I am writing tests involving multiple metrics with tradeoffs. When I make > a software change, the tests should show check for changes across any of > these metrics and show me that I was able to improve along one metric, but > at the expense of another metric. If I decide that these changes are > overall acceptable, I should be able to quickly modify the test based on > this new baseline. So far I am following this strategy using just > clojure.test and a bunch of custom code. > > Is there a testing library that would help with this? If not, does anyone > else have use for such a tool? > > *Current code* > > > https://github.com/ericlavigne/figurer/blob/master/src/figurer/test_util.clj > > *Details of my problem* > > I am writing performance tests for a Monte Carlo tree search library > called figurer. In the beginning, the tests were focused on avoiding > regression. I recorded that within 0.1 second figurer could find a solution > with value between 71.7 and 73.6 (based on trying this 10 times) and wrote > a test that would fail if the value was higher or lower than this range. > This was helpful for determining whether the algorithm was getting better > or worse, but did not help with why the algorithm was getting better or > worse. > > I made a change to the library to focus more on refinement of paths that > showed early promise, rather than spreading attention evenly across all > candidates. I expected that this change would substantially improve the > value found, but instead it slightly reduced that value. There were many > possible explanations. Maybe the more sophisticated algorithm did a better > job of choosing new paths to try, but at too much cost in time spent per > path evaluation. Maybe the new algorithm focused too much on refining a > path that showed early promise, ignoring a better path whose that got an > unlucky roll of the dice early on. I needed to compare a variety of > performance metrics between the old and new versions of the code. > > Commit for the unexpected results described above: > > Switch from random to UCT-based exploration (worse performance) > > https://github.com/ericlavigne/figurer/commit/97c76b88ac3de087b0cfa55005ab909aba21 > > I would like to track all of the following metrics to help me understand > the effect of each code change. > > 1) Estimated value of the chosen plan > 2) Closeness of the plan's first move to the best plan > 3) Number of plans that were considered (raw speed) > 4) Closeness of closest candidate first move to the best plan > 5) Number of first moves that were considered > 6) Evaluation depth of the chosen plan > 7) Maximum evaluation depth across all considered plans > > For each metric, I need to record a baseline distr