notes-computer-jasper-jasperCompilerNotes1

" I use Vim plugin called vim-godef. It is sort of like ctags, but better. It lets you jump to definition within your codebase as well as Go source. So you are just 'gd' away from learning what your function takes and returns. "

--

" >Also, if you want to refactor an interface, you have to go find all of its (undeclared) implementations more or less by hand.

Or use gofmt -r: http://golang.org/cmd/gofmt/ " --

"As a stand-in for real "X implements Y" declarations, you can always add various cheap statements that cause a compile-time interface-satisfaction check if there weren't such statements already--different phrasings I was playing with last night: http://play.golang.org/p/lUZtDdP5ia "

--

" ekmett Says:

September 20, 2013 at 2:19 pm

Michael Moser,

You’d be surprised.

Due to strict control over side-effects GHC is very good at rejiggering code into a form that does few to no allocations for the kinds of things you usually turn into an inner loop.

Supercompilation (http://community.haskell.org/~ndm/downloads/paper-supero_making_haskell_faster-27_sep_2007.pdf) can even “beat C” in some cases.

Stream fusion (http://metagraph.org/papers/stream_fusion.pdf) and the worker-wrapper transformation (http://www.cs.nott.ac.uk/~gmh/wrapper.pdf) are used heavily in the compiler and core libraries to make it so idiomatic haskell doesn’t have to be slow.

The vector library uses stream fusion to generate rather impressive unrolled loops. This is getting better now with Geoffrey Mainland’s work (http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/haskell-beats-C.pdf). Now idiomatic Haskell code like:

dot v w = mfold’ (+) 0 (mzipWith (*) v w)

is starting to even beat hand-rolled C that uses SSE primitives!

The key to being able to do these rewrites on your code is the freedom from arbitrary side-effects. That lets the compiler move code around in ways that would be terrifying and unverifiable in a C/C++ compiler. "

--

hmm, seems like we really need pure fns by default then? or at least a way for there to be no side effects by default within loops?

--

" waps 1 day ago

link

But there are several things java insists on that are going to cost you in performance in java that are very, very difficult to fix.

1) UTF16 strings. Ever notice how sticking to byte[] arrays (which is a pain in the ass) can double performance in java ? C++ supports everything by default. Latin1, UTF-8, UTF-16, UTF-32, ... with sane defaults, and supports the full set of string operations on all of them. I have a program that caches a lot of string data. The java version is complete, but uses >10G of memory, where the C++ version storing the same data uses <3G.

2) Pointers everywhere. Pointers, pointers and yet more pointers, and more than that still. So datastructures in java will never match their equivalent in C++ in lookup speeds. Plus, in C++ you can do intrusive datastructures (not pretty, but works), which really wipe the floor with Java's structures. If you intend to store objects with lots of subobjects, this will bit you. As this wasn't bad enough java objects feel the need to store metadata, whereas C++ objects pretty much are what you declared them to be (the overhead comes from malloc, not from the language), unless you declared virtual member functions, in which case there's one pointer in there. In Java, it may (Sadly) be worth it to not have one object contain another, but rather copy all fields from the contained object into the parent object. You lose the benefits of typing (esp. since using an interface for this will eliminate your gains), but it does accelerate things by keeping both things together in memory.

3) Startup time. It's much improved in java 6, and again in java 7, but it's nowhere near C++ startup time.

4) Getting in and out of java is expensive. (Whereas in C++, jumping from one application into a .dll or a .so is about as expensive as a virtual method call)

5) Bounds checks. On every single non-primitive memory access at least one bounds check is done. This is insane. "int[5] a; a[3] = 2;" is 2 assembly instructions in C++, almost 20 in java. More importantly, it's one memory access in C++, it's 2 in java (and that's ignoring the fact that java writes type information into the object too, if that were counted, it'd be far worse). Java still hasn't picked up on Coq's tricks (you prove, mathematically, what the bounds of a loop variable are, then you try to prove the array is at least that big. If that succeeds -> no bounds checks).

6) Memory usage, in general. I believe this is mostly a consequence of 1) and 2), but in general java apps use a crapload more memory than their C++ equivalents (normal programs, written by normal programmers)

7) You can't do things like "mmap this file and return me an array of ComplicatedObject?[]" instances.

But yes, in raw number performance, avoiding all the above problems, java does match C++. There actually are (contrived) cases where java will beat C++. Normal C++ that is. In C++ you can write self-modifying code that can do the same optimizations a JIT can do, and can ignore safety (after proving to yourself what you're doing is actually safe, of course).

Of course java has the big advantage of having fewer surprises. But over time I tend to work on programs making this evolution : python/perl/matlab/mathematica -> java -> C++. Each transition will yield at least a factor 2 difference in performance, often more. Surprisingly the "java" phase tends to be the phase where new features are implemented, cause you can't beat Java's refactoring tools.

Pyton/Mathematica have the advantage that you can express many algorithms as an expression chain, which is really, really fast to change. "Get the results from database query X", get out fields x,y, and z, compare with other array this-and-that, sort the result, and get me the grouped counts of field b, and graph me a histogram of the result -> 1 or 2 lines of (not very readable) code. When designing a new program from scratch, you wouldn't believe how much time this saves. IPython notebook FTW !

reply

upvote

PaulHoule? 9 hours ago

link

Hadoop and the latest version of Lucene come with alternative implementations of strings that avoid the UTF16 tax.

Second, I've seen companies fall behind the competition because they had a tangled up C++ codebase with 1.5 hour compiles and code nobody really understand.

The trouble I see with Python, Mathematica and such is that people end up with a bunch of twisty little scripts that all look alike, you get no code reuse, nobody can figure out how to use each other's scripts, etc.

I've been working on making my Java frameworks more fluent because I can write maintainable code in Java and skip the 80% of the work to get the last 20% of the way there with scripts..

reply "

--

" M: You just mentioned pretty-printers; what other programming tools and programming environments do you favor?

K: When I have a choice I still do all my programming in Unix. I use Rob Pike's sam editor, I don't use Emacs. When I can't use sam I use vi for historical reasons, and I am still quite comfortable with ed [laughing]; I know, that's even before you guys where born. And it's partly a question of history: I knew Bill Joy when he was working on vi.

I don't use fancy debuggers, I use print statements and I don't use a debugger for anything more than getting a stack trace when the program dies unexpectedly. When I write code on Windows I use typically the Microsoft development environment: they know where all the files are, and how to get all the include files and the like, and I use them, even though in many respects they don't match the way I want do business. I also use good old-fashioned Unix tools; when I run Windows I typically import something like the mks toolkits and I have standard programs that I'm used to for finding things and comparing them and so on.

" -- http://www.cs.cmu.edu/~mihaib/kernighan-interview/

--

Nock hints (lines 32-33 of the Nock 5k spec http://www.urbit.org/2013/08/22/Chapter-2-nock.html , operation 10 in its two forms): in one form, an argument (which may be a computed value) is given which is marked as a hint and then thrown away, in another form, an argument

--

" Actually, the hardest problem was getting the instrumentation agent to identify suspendable Clojure functions. This is quite easy with Java Quasar code as suspendable methods declare themselves as throwing a special checked exception. The Java compiler then helps ensure that any method calling a suspendable method must itself be declared suspendable. But Clojure doesn’t have checked exceptions. I though of using an annotation, but that didn’t work, and skimming through the Clojure compiler’s code proved that it’s not supported (though this feature could be added to the compiler very easily). In fact, it turns out you can’t mark the class generated by the Clojure compiler for each plain Clojure function in any sensible way that could be then detected by the instrumentation agent. Then I realized it wouldn’t have mattered because Clojure sometimes generates more than one class per function.

I ended up on notifying the instrumentation agent after the function’s class has been defined, and then retransforming the class bytecode in memory. Also, because all Clojure function calls are done via an interface (IFn), there is no easy way to recognize calls to suspendable functions in order to inject stack management code at the call-site. An easy solution was just to assume that any call to a Clojure function from within a suspendable function is a call to a suspendable function (although it adversely affects performance; we might come up with a better solution in future releases). "

---

http://gcc-melt.org/

--

http://nick-black.com/dankwiki/index.php/AVX

http://nick-black.com/dankwiki/index.php/VEX

--

this was really annoying. Also, something like "bundle" should be part of Jasper, not an add-on project.

" bshanks@bshanks:~/prog/backup-pinterest$ bundle install Fetching source index for https://rubygems.org/ 99999Using rake (10.0.3) Installing addressable (2.3.2) Using bundler (1.0.17) Using mime-types (1.19) Installing nokogiri (1.5.6) with native extensions /home/bshanks/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/installer.rb:533:in `rescue in block in build_extensions': ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError?)

        /home/bshanks/.rvm/rubies/ruby-1.9.2-p290/bin/ruby extconf.rb checking for libxml/parser.h... no

libxml2 is missing. please visit http://nokogiri.org/tutorials/installing_nokogiri.html for help with installing dependencies.


* extconf.rb failed * Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options.

"

http://nokogiri.org/tutorials/installing_nokogiri.html

"

Ubuntu / Debian

Ubuntu doesn’t come with the Ruby development packages that are required for building gems with C extensions. Here are the commands to install everything you might need:

  1. ruby developer packages sudo apt-get install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 sudo apt-get install libreadline-ruby1.8 libruby1.8 libopenssl-ruby
  2. nokogiri requirements sudo apt-get install libxslt-dev libxml2-dev sudo gem install nokogiri

Although, if you’re using Hardy (8.04) or earlier, you’ll need to install slightly different packages:

  1. nokogiri requirements for Hardy (8.04) and earlier sudo apt-get install libxslt1-dev libxml2-dev

As John Barnette once said, “Isn’t package management convenient? :)” "

--

http://prog21.dadgum.com/6.html

" More than just executing code, I'd want to make queries about which registers a routine changes, get a list of all memory addresses read or modified by a function, count up the cycles in any stretch of code. "

(about assembly, but still relevant)

--

"There's a simple rule about tail recursive calls in Erlang: If a parameter is passed to another function, unchanged, in exactly the same position it was passed in, then no virtual machine instructions are generated....Perhaps less intuitively, the same rule applies if the number of parameters increases in the tail call. This idiom is common in functions with accumulators"

"In fact, just about the worst thing you can do to violate the "keep parameters in the same positions" rule is to insert a new parameter before the others, or to randomly shuffle parameters."

"These implementation techniques, used in the Erlang BEAM virtual machine, were part of the Warren Abstract Machine developed for Prolog. "

-- http://prog21.dadgum.com/1.html

--

" The Go compiler does not support incremental or parallel compilation (yet). Changing one file requires recompiling them all, one by one. You could theoretically componentize an app into separate packages. However it appears that packages cannot have circular dependencies, so packages are more like libraries than classes. " -- http://ridiculousfish.com/blog/posts/go_bloviations.html#go_compiletimes

--