I translated a simple C program to x86_64 and it was slower - <AUTHOR> https://ecc-comp.blogspot.com/2020/04/i-translated-simple-c-program-to-x8664.html <comment><USER2> The assembly is not bad for a beginner but far from optimal. A few things that stand out from a quick glance:

1) Try to load things sequentially don't load from offset 32, then 0, then 16.

2) Don't use the loop instruction

3) this code:

      dec  n
      cmp  n, 0
      jne  1b

Can be replaced with:

      sub n, 1
      jnz 1b

Which will actually be executed by the processor as a single instruction (macro-op fusion).

4) Interleave your expensive instructions with less expensive ones. Try to interleave multiple dependency chains to let the processor see more of the parallelism.

Your two divisions one after another will be limited by available execution units capable of doing the divide.

5) Lastly align your loop labels to 16-byte offsets. The assembler will do this for you with the ALIGN directive.

<comment><USER3> Are there linters that will overlay compiler-tier optimization hints on top of handwritten assembly?

<comment><USER4> The closest thing would be the _Godbolt Compiler Explorer_ :

[https://godbolt.org/](https://godbolt.org/)

<comment><USER5> It is nice tool for online exploration, but not as V-Tune.

</comment></comment></comment></comment><comment><USER6> You have five bodies and 16 sse registers. The entire state of your simulation can fit into register space and you dont need to ever access memory during the stepping part of your code. You can loop unroll all gravity interactions so you end up with one large branchless memoryless block of code. Now that its completely inline you can rearrange your dependencies based on expected latency and throughput of operations ([https://software.intel.com/sites/landingpage/IntrinsicsGuide...](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=MMX,SSE,SSE2,SSE3,SSSE3,SSE4_1,SSE4_2&text=sqrt&expand=5385))

Then after that you can merge the operations where you can. (for SSE4 at most you are going to get is 2x because you are using doubles)

You may think the full inlining is cheating but the compiler has the same information as your bodies list is entirely constant. (since your dt and your masses are constant they can also potentially be folded).

<comment><USER7> Full inlining might be slower if the branch is easy to predict

</comment></comment><comment><USER8> This is the n-body problem from the Computer Language Benchmark Game with the attribution to the original author removed.

[https://benchmarksgame- team.pages.debian.net/benchmarksgame/...](https://benchmarksgame- team.pages.debian.net/benchmarksgame/program/nbody-gcc-3.html)

The faster programs usually use SIMD.

[https://benchmarksgame- team.pages.debian.net/benchmarksgame/...](https://benchmarksgame- team.pages.debian.net/benchmarksgame/performance/nbody.html)

<comment><USER9> Any idea what's going on with the _mem_ values in the listing in your second link?

Wouldn't expect a C++ implementation to use 200x the memory of a C implementation. Different algorithms presumably? Or a significant compiler optimisation being missed?

<comment><USER10> Maybe because the cpp version includes stdlib on top of stdio?

<comment><USER9> Ah, of course. So the problem doesn't involve any real allocations, and it's just the language overhead that we're seeing.

</comment></comment></comment></comment><comment><USER11> Sometime around 2000, I tried to hand optimise an image processing routine in x86 assembly. Previously I'd only done 6502.

My first attempt was massively slower than the compiled code. I had to get into the whole pipelining that was going on and other hardware optimisations.

When I discovered putting a NOP in a tight loop sped up the code, I realised I wasn't going to beat the compiler most of the time!

<comment><USER12> Really insightful comment.

It's true. C compilers are so optimized, the day of re-write in assembly have long passed for most of us.

<comment><USER13> it is the dance between compilers and chip designs that unmakes hand work.

</comment></comment></comment><comment><USER14> I think the point was adequately made. You can, of course, write better assembly, and you can of course write the exact same assembly a compiler would. But if all of the suggestions for optimization are things compilers would do anyways, you are better off coding in a higher level, portable language in the first place, and only dropping down to asm when it is sufficiently beneficial.

All nitpicking about the quality of the assembly is valid of course, but it does inadvertently help prove the point, especially since most or all of these things are things compilers do today.

<comment><USER15> Well, you have to also consider that most of us write a lot of high level code and very little, if any, assembly code, so we shouldn't expect to be good at writing high performance assembly without practicing. I've seen some rather amazing high performance hand-written assembly code, by people who write it often, but I certainly wouldn't be able to do it, without a lot of study and practice.

Of course, for most people and most uses, its not worth the effort.

<comment><USER14> I frequently make this point so I may sound like a broken record, but I believe this is more or less a fallacy.

Again, the point isn't that better assembly couldn't be written. It's that it most likely wouldn't be significantly better than the compiler because all of the suggestions are things compilers would be doing anyways. There are some cases where this isn't true, especially when dealing with vectorization, but those are mostly just exceptions (and intrinsics often offer easier ways to do such optimizations...)

But here's the point that I feel is often ignored when it comes to programming language debates in general: just because you are experienced with and aware of advanced usages of the environment you're programming in, does not mean the complexity and especially cognitive overhead of said complexity has disappeared. Looking at the C version, it doesn't really look especially optimized, which is not really something that you would see in assembler, at least not in my opinion. Complexity adds up over time; abstractions are the antidote to that problem.

On top of that, assembly language is obviously not portable, which IMO is even more reason to use a high level language and drop to asm only when needed; you can easily swap implementations and have a fallback for architectures that aren't specifically optimized.

<comment><USER15> If you don't study and practice it, how can you possibly know how to write good code (in any language)? In assembly, if you've never been exposed to eg the simd instructions, or aligned memory access or cache or branch prediction or instruction level parallelism, how can you expect to write performant assembly code? Experience and knowledge doesn't just appear.

I'm not arguing that it's worth it or that it's easy to beat the compiler. I certainly am not going to bother writing assembly (maybe some intrinsic for SIMD but certainly not raw assembly, outside of embedded systems, although even then it's not really worth it usually).

I'm simply saying that you can't expect to be good at something unless you practice it.

But that doesn't mean people shouldn't try but to learn. For example, somebody has to implement the optimisations isn't he compiler and that person needs to have a great understanding of how to produce high performance assembly code. Plus learning new things is always worthwhile if you have the time.

<comment><USER5> In Assembly, even if you manage to beat the compiler, it might be a pyrrhic victory, because it might be lost when trying the same benchmark in another CPU or after getting a microcode update.

During the 80's and early 90's it was a different matter, because CPUs were dumb, hardware was relatively static specially on 8 and 16 bit consumer systems and high level optimizers were pretty dumb given the resource constraints of those platforms.

<comment><USER15> I'm not debating whether or not its a worthy endeavour though, I'm only saying that you can't expect good performance out of assembly code unless you practice writing high performance assembly code. Most of us have a lot of experience with high level languages, so that we can write well performing high level code makes a lot of sense, but we shouldn't expect that we can just "drop down to assembly" and get a performance boost, but that also doesn't mean that its never possible, for the people who do actually do this a lot (eg the x264 people writing hand crafted SSE/AVX code)

<comment><USER5> It is an herculean effort trying to master modern Assembly.

Back in the day, you could easily know all opcodes for a given CPU, and their clock cycle timings.

This is the SIMD guide for the Intel CPUs,

[https://software.intel.com/sites/landingpage/IntrinsicsGuide...](https://software.intel.com/sites/landingpage/IntrinsicsGuide/)

Which is only a tiny subset of all the opcodes that a modern Intel CPU is able to understand, let alone what AMD also offers.

You need tools like VTune from each CPU vendor to actually understand the CPU clock timings of each opcode in micro-ops (microcode execution unit).

While you can master a specific subset, like knowing AVX instructions, mastering Assembly back to back like in the old days, only when writing Assembly for stuff like small PIC microcontrollers.

Trying to master a language like C++ is easier, which says a lot about how modern CPUs look like.

</comment></comment></comment></comment></comment></comment></comment><comment><USER16> These days, it's not only compilers that are optimizing for the particulars of the CPU, but CPUs optimizing for compiled code. My favorite examples of this are the inconsistent and sometimes downright crappy performance of "rep" string instructions and the "loop" instruction. Both seem like ideal easy things to write for handwritten assembly, yet the performance of both constructs can be quite awful on certain modern CPUs compared to the naive loops that compilers output. Much of this can be blamed on the fact that compilers rarely use either construct, so chipmakers had no reason to make either of them efficient (and, indeed, seem to have actually pessimized them on some chips!).

<comment><USER17> REP MOVS is still extremely fast --- and also small. It'll copy cacheline- sized chunks if the size is large enough.

LOOP is a bit of a weird case. I've seen it benchmark both slower and faster than dec/jnz depending on the surrounding instructions.

<comment><USER18> loopXX instructions do not use CPU LSD (Loop Stream Detector) while cmp/jnz construct takes advantage of it. This speeds up some small loops. Also, there are some rules in intel manuals for instructions within cmp/jnz loop like no mismatched push/pop, etc.

now, does anyone know why?

<comment><USER17> _like no mismatched push /pop, etc._

My guess is virtual stack pointer update prediction latency.

To expand on that, Intel's CPUs have had for a long time a separate piece of hardware dedicated to a "virtual" stack which speeds up push/pop instructions. If pushes and pops are not mismatched, then all stack operations can stay entirely within that and there's no need to update the "real" stack pointer nor stack entries upon leaving the loop.

<comment><USER18> Thank you for your answer! Any idea why would loops not use LSD when programmed using loopXX instructions but would use when cmp/jnX is used?

</comment></comment></comment></comment></comment><comment><USER19> Author really needs to put the assembly under a profiler. Others have mentioned things like poor instruction selection (loop).

In my experience it's good to first attempt a rewrite in C using intrinsics. This gets you thinking about data and register layout at a high level and let's you better identify mid level optimizations before committing to assembly.

</comment><comment><USER20> lol, I did not expect this. I submitted this myself yesterday and it got 2 upvotes.

To the people with suggestions, especially jdsully: thank you! I will probably give these a shot.

To the people who say "blah blah someone who doesnt know x giving an opinion on y blah blah", ok, what is wrong with sharing an experience? I'm not sure how to interpret this other than you take what I write way too seriously? It's an explorative piece...

Edit: I wanted to mention too that it's really cool reading other's stories around this topic. Thank you for sharing!

</comment><comment><USER17> The author picked a case in which compilers can be faster, because it turns out to be the sort of code that compilers are usually optimising for; code that contains plenty of scientific/numerical computations. Thus the result is not so suprising.

On the other hand, with branchy "business logic"/general-purpose code and algorithms that can't really be vectorised, it's pretty easy to beat a compiler with handwritten Asm --- on speed, size, or often both.

<comment><USER21> Please show us a proof - I have yet to see any non-toy program / routine with complex control flow written in assembly beating a modern optimizing compiler.

You can optimize a small routine. Anything that's not a toy rapidly becomes impossible to optimize by hand.

Just the register allocation itself can be a gigantic pain to do by hand, even with a limited register set of x86, let alone other RISCs with much larger register files.

EDIT: Added clarification in the wording.

<comment><USER17> [http://menuetos.net/](http://menuetos.net/)

 _Just the register allocation itself can be a gigantic pain to do by hand, even with a limited register set of x86,_

Actually, that's one of the main advantages of using Asm --- compilers are relatively horrible at register allocation, because they don't take a more "holistic" view of the program, and end up shuffling values between registers or registers and memory far more often. This is why handwritten Asm has a unique "texture" to it.

 _let alone other RISCs with much larger register files_

There's much less room for optimisation with handwritten Asm on a RISC, because with x86 the opportunities are precisely those the compiler can't easily see, unlike a very uniform and boring RISC.

<comment><USER21> You say those things. Please show me an example of a real world, general purpose, non toy sized program or routine that is hand optimized and shown to perform better than the optimizing compiler.

<comment><USER22> OpenBLAS

<comment><USER23> GEMM is a fairly special case, but the case is unproven as far as I can see. The OpenBLAS kernels are certainly bigger than they need be, but it's not clear to me they satisfy the request (especially addressing "holistic" treatment of registers), and "OpenBLAS" isn't a performance measurement.

Since I'm interested in this, I'd like to see the case to reproduce with an analysis of the performance difference. BLAS developers have made statements about GCC optimization failures (at least vectorization) that aren't correct in my experience with at all recent GCC. BLIS' generic C kernel already runs at ~60% (I forget the exact number) of the speed of the Haswell assembler code for large DGEMM without any tuning attempt, perhaps with GCC extensions. (I didn't check whether the blocking is right for Haswell or pursue an analysis with MAQAO or something.)

</comment></comment></comment></comment></comment></comment><comment><USER24> Not too long ago while optimizing some x86 code on my i7-4900k, I discovered that at least for this code it was appreciably faster to do

        mov [mem], reg
        div [mem]

rather than simply

        div reg

I'm no asm guru, but I expected the L1 cache to be slower than a register, and certainly not a round-trip via L1 to be several percent faster.

The reason I stumbled upon this was that the compiler emitted the first variant and I tried to optimize it to the second, but lost speed. That's when I decided I'll stick to optimizing my high-level code...

FWIW this div was in a somewhat tight loop, but sadly I've totally forgotten the rest of details. I do recall adding nops here and there to play with loop alignment, it wasn't that.

<comment><USER25> Modern processors are so complex that changes sometimes have paradoxical consequences, simply in a kind of chaotic way. That seems to be the case in what you describe. Those are typically not robust effects though, and changing seemingly completely unrelated things might put the perf right back at what you expect.

<comment><USER24> Indeed. Having slept on it, I do recall someone mentioning that my performance discrepancy could be related to busy load/store ports. If the issue is that it doesn't have free reg-reg load/store capacity but reg/mem and mem/reg is otherwise available, then it makes kinda sense I guess.

But in that case the performance could totally change again if just one more instruction is added.

</comment></comment></comment><comment><USER26> This comparison is a bit unreasonable because the Benchmarks Game has a heavy selection effect going on; if the compiler generates bad code for a program, people won't submit it.

There are plenty of instances where compilers go haywire and generate code far worse than even a half-competent novice would, because compilers don't know the same things about your code that you do.

<comment><USER27> > if the compiler generates bad code for a program, people won't submit it

Seems just to be speculation.

Might we just as easily speculate that — _if the compiler generates bad code for a program,_ that still looks a lot better than the comparison interpreters so _people will submit it_ ?

</comment></comment><comment><USER28> @fallat:

I started to take a look at your problem, but I wasn't able to run the code that you posted to test.

For the C code, the "#include" statements at the top are missing their <header.h>. Easy to solve now that you posted the link to the original, but maybe you could fix?

For the assembly, you are relying on "list.macro", which I couldn't find. Could you post this, or even better link to a repository that can be used?

Separately, it would probably be helpful to post the exact model number of your processor. Speed doesn't (shouldn't?) really matter, but the "generation" is essential.

Also, I don't think you mention the number of iterations you are running for your timing. [I see now in the assembly that you seem to be using 5000000?]

Post a bit more info, and someone here (maybe me, maybe not) will figure it what's causing the slowdown.

<comment><USER20> Oh whoops, I'll add it in. EDIT: It's a damn blogger encoding error.

Yep, it's 5 million iterations.

I will update the post with list.macros immediately!

This is my CPU: Intel(R) Pentium(R) CPU N3700 @ 1.60GHz

Edit: it is updated. :) list.macros has been inlined in the snippet.

<comment><USER28> Great, I'll take a look in a bit, although it might take me until tomorrow to have time to do much with it.

In the meantime, I'll mention that my first quick discovery is that clang seems to be significantly faster than gcc on the standard C code. The ratio changes with different versions and compilation options, but on Skylake with "-Ofast -march=native" I find clang-6.0 to be almost twice as fast as gcc-8. So if you have clang installed, check and see if it might be a better baseline.

Also, what system are you running? This shouldn't make a difference with execution speed, but will make it easier to make tool suggestions. If you are running some sort of Linux, now would be a good time to get familiar with 'perf record'!

Edit: > Intel(R) Pentium(R) CPU N3700 @ 1.60GHz Hmm, that's a "Braswell" part, which unfortunately isn't covered in Agner's standard guide to instruction timings ([https://www.agner.org/optimize/microarchitecture.pdf](https://www.agner.org/optimize/microarchitecture.pdf)) and I'm not familiar with it's characteristics. This might make profiling a little more approximate.

<comment><USER20> Debian buster; and if you're going to make a comparison, I'm just saying this just in case, you must force it to only use SSE3 and no later. :)

I added the build instruction for the assembly but I'll add it here too: gcc nbodies.s -no-pie -o nbodies.out

Shoot me an email if you get around to it! :D

I'll check out perf record.

<comment><USER28> OK, I'm now able to test your code!

The preliminary results I get disagree with what you are seeing. I'm not sure if this is my error, your error, or just genuine differences between processors. Specifically, on Skylake, I get your assembly to be much faster than GCC, although slightly slower than Clang. And that's without trying to use options to limit the compiler:

      gcc-8 -Ofast -march=native bodies.c -Wall -lm -o bodies_gcc_Ofast_native_c
      perf stat bodies_gcc_Ofast_native_c 5000000
      2,031,645,589 cycles       #    3.691 GHz
      2,181,200,813 instructions #    1.07  insns per cycle

      gcc bodies.S -o bodies_S
      perf stat bodies_S
      1,293,433,853 cycles         #    3.691 GHz
      2,641,011,827 instructions   #    2.04  insns per cycle

      clang-6.0 -Ofast -march=native bodies.c -Wall -lm -o bodies_clang_Ofast_native_c
      perf stat bodies_clang_Ofast_native_c 5000000
      1,158,569,067 cycles       #    3.691 GHz
      2,331,116,659 instructions #    2.01  insns per cycle

Not having understood the assembly yet, my guess from skimming is that the compiler isn't able to vectorize this code well, and thus the SSE/AVX distinction isn't going to matter much. "-Ofast" should be comparable to "-O3" here, although I don't recall the exact differences. I didn't use "-no-pie" with your assembly, but don't think this matters.

Are you able to do a similar comparison and report results with "perf stat"? Cycles and "instructions per cycle" are going to be better metrics to compare than clock time. No hurry. I'm East Coast US, and done for the night.

Edit: A quick glance at "perf record" and "perf report" suggests that clang is slightly faster than you (on Skylake, using these options) because it's making use of fused multiply-adds. Which slightly contradicts what I said about the SSE/AVX distinction not mattering, although it's only a minor effect. For both routines, the majority of the time spent is in the chain starting with the division. I'm wondering if there is some major difference in architecture with Braswell --- perhaps it only has a single floating point multiplication unit or something? Or one of the operations is relative _much_ slower.

Edit 2: Looking at [https://en.wikichip.org/wiki/intel/cores/braswell](https://en.wikichip.org/wiki/intel/cores/braswell), I now see that Braswell is the name of the "system on a chip", and the CPU microarchitecture is Airmont. This isn't in Agner either, but at least I've heard of it! [https://en.wikichip.org/wiki/intel/microarchitectures/airmon...](https://en.wikichip.org/wiki/intel/microarchitectures/airmont) says Airmont is basically the same as Silvermont, which Agner does cover, so we should be able to figure out timings. See page 320 here: [https://www.agner.org/optimize/instruction_tables.pdf](https://www.agner.org/optimize/instruction_tables.pdf).

Edit 3: I hadn't actually looked at your code yet. So you are trying to vectorize, it's just that you are limited in doing so because you can only do 2 doubles at a time. But since you are working in 3D, this doesn't fit evenly, so you do [x,y] then [z,null]. Thus you expected it to be something like 1.5x faster on your processor, and instead it comes out 2x slower. I think the issue might be that your processor doesn't really have full vector units --- instead it's doing some sort of emulation. Look closely at the timings on Page 338 of the instruction table I linked in Edit 2. Note that DIVPD takes just about twice as long as DIVSD. Then check Skylake on Page 252 -- same time for packed and single XMM. While this isn't the full answer, I think it's a strong hint at the issue. The quickest fix (if you actually want to make this faster on your processor) is to use the single instruction for the [z,null] case. This isn't going to help much overall, since it takes twice as long for the packed, but it might at least get them back to parity with the compiler! If you actually want higher speed from your vectorization, you may have to switch to a processor that has better vectorized speeds.

<comment><USER20> I just want to say: wow! You are showing me something I bet many others are really not aware of: degraded SSE performance in these types of processors! Your DIVSD vs DIVPD comment makes a lot of sense too. Man I feel this HN thread has been just a gold mine of this kind of information.

What is the speed with restriction to SSE3? That would finalize the tests.

Do you mind if I directly quote you in a follow up post? This is really good stuff.

<comment><USER28> > What is the speed with restriction to SSE3? That would finalize the tests.

I think this is the right incantation to restrict to SSE3:

      clang-6.0 -O3 bodies.c -msse3 -Wall -lm -o bodies_clang_O3_sse3_c
      perf stat bodies_clang_O3_sse3_c 5000000
      1,470,870,787 cycles       #    3.691 GHz
      3,391,153,749 instructions #    2.31  insns per cycle

      gcc-8 -O3 bodies.c -msse3 -Wall -lm -o bodies_gcc_O3_sse3_c
      perf stat bodies_gcc_O3_sse3_c 5000000
      2,256,550,525 cycles       #    3.691 GHz
      3,306,361,186 instructions #    1.47  insns per cycle

It would be interesting to analyze the difference between GCC and Clang here. Just glancing without comprehension, it looks like one big difference is that Clang might be calling out to a different square root routine rather than using the assembly builtin. Hmm, although it makes me wonder if maybe that library routine is using some more advanced instruction set?

> Do you mind if I directly quote you in a follow up post?

Sure, but realize that I'm speculating here. Essentially, I'm an expert (or at least was a couple years ago) on integer vector operations on modern Intel server processors. But I'm not familiar with their consumer models, and I'm much less fluent in floating point. The result is that I know where to look for answers, but don't actually know them off hand. So quote the primary sources instead when you can.

Please do write a followup, and send me an email when you post it. My address is in my HN profile (click on username). Also, I might be able to provide you remote access to testing machines if it would help you test.

</comment></comment></comment></comment></comment></comment></comment><comment><USER29> I would compile the C code with the -S option to output your C code as assembler, and then compare them to see what decisions were made by the (pre)compiler that made the compiled C code run faster than your hand-wrung code. The code is short enough that you should be able to relate the different parts and easily see the "improvements".

This is how I learned to program assembler for Linux. I already knew TASM / MASM / a86 assembler languages for DOS/Windows - all similar but different in their own regards - but gas is a different un-backward beast, and of course the system calls are totally different between Linux and DOS/Windows.

For example, here are 6 different ways to program helloworld on an ARM cpu (Raspberry Pi) running Raspbian Linux: [https://github.com/ksaj/helloworld](https://github.com/ksaj/helloworld) I kept each of them as close to the same as possible, so that it is easy enough to see the differences in how each call is set up before execution.

I'm sure if you added timer code before and after the example code, you'd very quickly discover which methods are more optimal and then begin to dissect why that would be, and how to use that knowledge in future programs.

Keep in mind that the order of opcodes will impact execution speed, because of the many techniques modern cpus use to speed things up (branching, prediction, encoding techniques, entirely rewriting opcodes to something else with the same functionality - eg, most compilers understand that mov ax,0, sub ax,ax and xor ax,ax all do the same thing), etc.

</comment><comment><USER30> I have a good real-world counter example: The game Rollercoaster Tycoon was written in assembly and ran full speed on a Pentium 1.

OpenRCT2 is a code conversion to C++. You can turn off all the visual tweaks they have implemented on top of the original game and it still requires significantly more CPU time than the original. And thats with a compiler being able to take advantage of modern CPU instructions while the original game can't do that.

<comment><USER25> Maybe the slowness is more due to poor high level design for the problem (& if you want an highly optimized result)? E.g. AoS everywhere instead of SoA if needed. I don't know I have not checked the source code, but it is a possibility.

</comment></comment><comment><USER31> I came to the same result three years ago by writing the exact same problem into x86-64 asm, I guess I didn't think of it as something worth of sharing.

[https://github.com/franciscouzo/nbody- asm](https://github.com/franciscouzo/nbody-asm)

<comment><USER32> Unfortunately the links in the README file in that repo no longer resolve ([https://benchmarksgame.alioth.debian.org/](https://benchmarksgame.alioth.debian.org/))

Might you or anyone else have the updated link(s) to the nbody problem?

<comment><USER33> [https://benchmarksgame- team.pages.debian.net/benchmarksgame/...](https://benchmarksgame- team.pages.debian.net/benchmarksgame/performance/nbody.html)

Looks like the subdomain was changed at some point.

</comment></comment></comment><comment><USER34> All this usually proves is that compilers are smarter than you think.

You can get some gains from SIMD code (i.e. autovectorization is hard), e.g. you've laid out data deliberately but the compiler doesn't quite see it, but modern CPUs are so complicated even executing scalar instructions that I wouldn't bother. I think optimizing memory is more productive half the time anyway, most programs don't spend that much time number crunching.

<comment><USER35> This program is a special case because the whole state fits in registers unless the compiler detects this a human should be able to beat the compiler. Even unrolled the code would fit in the L1 instruction cache.

</comment></comment><comment><USER36> Some optimisation can only be performed after the fact (in as much as profile of a real run against real data informs the branch prediction and choices in speculative execution and order)

Some execution fails: hardware has pathological instruction sequences which force sub optimal choices to be made.

Alternative algorithms cannot always be identified from an instruction sequence. What if a higher order function identifed better seeds and led to faster detection in a large field of candidate solutions?

</comment><comment><USER37> What is the best book for learning the nuances of x86 assembly?

<comment><USER5> It is now about 20 years old, but you can start with "Zen of Assembly Language" and carry on with "Graphics Programming Black Book".

[https://github.com/jagregory/abrash-zen-of- asm](https://github.com/jagregory/abrash-zen-of-asm)

[https://github.com/jagregory/abrash-black- book](https://github.com/jagregory/abrash-black-book)

</comment></comment><comment><USER38> I recently had some fun writing arm64 assembly. My experience is that hand written assembly is faster if you apply the same cheats that the compiler uses. 3 things to keep in mind: 1) Make use of the registers; 2) Avoid branches; 3) Get familiar with the instruction set and make good use of them.

[https://litchie.com/2020/03/arm64-fib](https://litchie.com/2020/03/arm64-fib)

</comment><comment><USER39> I once found some book on MC68000 programming on the Macintosh. In a chapter on graphics, the book presented an assembly routine for drawing a filled circle and bragged about how machine code gets it down to just .25 seconds. I went, "what???" and read the code: it was calling an integer square root subroutine for every scan line of the circle. Not even a good integer square root routine.

<comment><USER40> [https://www.folklore.org/StoryView.py?story=Round_Rects_Are_...](https://www.folklore.org/StoryView.py?story=Round_Rects_Are_Everywhere.txt) might be relevant?

<comment><USER41> Interesting but it left me wondering what was his fast routine for drawing rounded rects. The squarical formula?

<comment><USER42> Here's my guess: the Mac's drawing routines all did clipping in software. That was accomplished by having drawing of rectangles, circles, ovals, polygons and rounded rectangles (for various operations such as erasing or filling them, drawing a frame along the outside, inverting the bits inside) all come down to:

\- compute the set of bits (called a 'region') to operate on

\- call the appropriate function to erase/fill/… that region

I would guess drawing ovals was done this way:

\- create a region for a circle with radius equal to that of the radius of the corners.

\- insert horizontal parts to each row of bits in the region to 'stretch' the region horizontally into a rounded rectangle that has the correct width, but is only as high as the circle.

\- insert vertical parts to each column of bits in the region to 'stretch' the region vertically into a rounded rectangle that has the correct width and height.

The first step was identical for the code for drawing circles; the region data structure made the last two operations cheap; they did not require any memory allocations. You had to walk the entire data structure, but for small corner radiuses, it wasn't that large. Also, one could probably optimize for speed by doing that while creating the region for the circle.

I can't find a good description of the region data structure, but [https://www.folklore.org/StoryView.py?project=Macintosh&stor...](https://www.folklore.org/StoryView.py?project=Macintosh&story=I_Still_Remember_Regions.txt) might be enough for some to figure out how it, conceptually, worked.

<comment><USER43> My guess is they didn't even need to be fast, just render once when the window is configured and keep a cache of rounded corners in the window system complete with the masks. They're tiny, and symmetrical.

<comment><USER42> Compute once when the window is created or resized is what happened, yes, but that doesn't work when using them for buttons (unlike MS Windows, where every control is a 'Window', on Mac OS controls inside a window didn't have their own drawing context), or when using them for window content (e.g. in a drawing program)

And remember: the original Mac had about 28 _kilo_ bytes of RAM free for applications. The system unloaded icons, code and fonts that were available on disk all the time. Few objects were 'tiny' at the time.

</comment></comment></comment></comment></comment></comment><comment><USER44> "I haven't looked particularly close at it but I'm sure someone could spot why mine is almost 2x as slow."

Isn't that the whole point?

</comment><comment><USER45> Maybe aligning functions would help. The compiler likely does that for the C version.

</comment><comment><USER46> Interesting, but personally I'd be more interested with the feasibility of X programming language with GC translated to C program and C version was slower type of article.

</comment><comment><USER47> Compiler beats novice assembly programmer ¯\\_(ツ)_/¯

</comment><comment><USER48> Maybe I missed it - but did the author list compiler options? I wonder if the handwritten assambler was slower than a compile with optimizations off, too.

<comment><USER49> From the article: "The gcc options for the C code used was -O3 -lm, because my processor doesn't support AVX".

</comment></comment><comment><USER50> One thing I was told in college is that compilers are much better at assembler than people.

</comment><comment><USER51> "Let me quickly set the scene for when I started: I had zero exposure to x86_64 before this."

So, to sum it up: guy who has no clue writes worse code then one generated by a decent compiler.

</comment><comment><USER52> >The saying that "processors are optimizing for C" is totally correct.

I thought that the latest consensus on HN was that C is nowhere closer to the hardware.

<comment><USER53> C is close to the interface the hardware presents you – that is, the instruction set – but far from what the hardware actually _does_.

Caching, out-of-order execution, branch prediction, speculation... all of those things are just as opaque to assembly as they are to C.

<comment><USER54> > C is close to the interface the hardware presents you – that is, the > instruction set – but far from what the hardware actually does.

C isn't even close to that anymore, now that so many processors have SIMD ISAs which C can't usefully model.</comment></comment></comment>


An abstraction called text styles – How to save yourself from a typographic mess - <AUTHOR> https://www.reaktor.com/blog/an-abstraction-called-text-styles/ <comment><USER2> author, ama

<comment><USER3> I know page design ≠ implementation of design but the poor font colour pairing doesn't lend much credibility.

<comment><USER4> I don't get it - what's wrong with the colour pairing?

<comment><USER3> The greyscale text is way too light. Very hard on the eyes.

<comment><USER4> Hmm, it's possibly more the font, your system's font rendering, and/or your display than the colour.

It's an easy pass for WCAG AA with 5:1 contrast ratio, but I think it's marginal for WCAG AAA as it's about 20px in size, but not bold.

If you're finding that hard on the eyes it might pay to check your display's brightness with a colorimeter. Most displays are far too bright out of the box.</comment></comment></comment></comment></comment>


Why We Need Trolls - <AUTHOR> http://nerdr.com/why-we-need-trolls/

<comment><USER2> It does hurt people. It means that people who want to discuss something calmly and rationally can't, because the troll keeps derailing the conversation.

<comment><AUTHOR> Do trolls really derail a conversation or encourage it along? Particularly on sites like Reddit, i've found them to be vilified, yet the way they can instantly cause a change of perspective to counter groupthink is vastly under appreciated. They're useful, else they wouldn't have existed for so long.

<comment><USER2> Trolling is the art of winding people up. Offering a different perspective is not trolling. Offering the same different perspective repeatedly and refusing to take it to a thread where it's already been discussed to death is an example of trolling; it derails and does not encourage.

Trolls exist because some people enjoy winding people up. Being useful isn't a motive.

</comment></comment></comment><comment><USER3> You're welcome :P

As long as the people who don't see it all as a joke are sufficiently contained, then yes, it adds breadth to a conversations of comments. Someone mentions Hitler, someone else is reminded of something clever the Germans do.</comment>


Discovery of peculiar periodic spectral modulations in some solar type stars - <AUTHOR> https://arxiv.org/abs/1610.03031 <comment><USER2> This is about as legit of ETI search as there can be (real data, experimental design, and publication). Nice to have some sanity in the search (albeit, their enthusiasm is clear).

At best they find ETI, at worst they discover some strange chemical compositions of galatic halo stars.

<comment><USER3> >> At best they find ETI

"At best"?

Consider for a moment that if we ourselves ever get to advance our technological civlisation to the point where we are capable of interestellar travel we're very likely to start sending out signals to other civilisations on planets around stars that could support human life not to make friends with those civs but to make it easier for us to find and colonise those planets.

"Colonise" as in take over, exterminate their native species and live happily ever after. As any intelligent species with an ounce of brain is bound to do to other intelligent species dumb enough to respond to such a signal.

Luckily, this is most probably just some weird star phenomenon and we're all safe, for now.

<comment><USER4> But how can such a baiting civilization know that it's more powerful than the baited civilization, and that it itself is not falling into a trap?

</comment></comment></comment><comment><USER5> Ermanno Borra, who first speculated that periodic Extra-terrestrial signals could be detected using Fourier transform analysis on all those old piles of astronomical spectra data we have lying around, also states that "technology now available on Earth could be used to send signals having the required energy to be detected at a target located 1000 light years away"! I vote we try running _that_ experiment for a more conclusive answer to age old conundrum: are we truly alone in the universe?

<comment><USER6> My vote is for not running experiments when we may not like the results. (But we won't do it anyway - our votes do not matter.)

There are plenty of passive ways to gather the same data, that don't broadcast our existence into a galaxy we know nothing about. Let's use those first, and after we learn, decide if we want to talk back.

<comment><USER7> Agreed. Based on billions of years of living in a multi-species planet, observation and intelligence-gathering is both prudent and non-violent. Running with our arms waving, yelling "Hey guys! We're here!" without further information about who we are talking to is an extremely, extremely bad idea.

We've got millions of years to figure out what to do. There's no rush. It would be amazing to finally know we're not alone. That's a great first step.

<comment><USER8> Something interesting to think about is we live on a G-sequence star so detecting life mostly in G and K stars won't take much argument WRT G.

However one interesting idea WRT K series, is as a dwarf, I bet a "nearby" sufficiently bored, yet paranoid, civilization could mess with a K series by periodically blasting it remotely with a truly huge laser/maser and mirror system. I'm not talking about bored ham radio operator level of commitment but a suitably high tech advanced civilization could possibly pull this off. "Well, we're building a solar system wide asteroid defense system anyway, so letting the scientists do research 1% of the time when nothing else is going on, won't hurt too much"

So possibly the G series civilizations are rather psychologically optimistic, or pessimistic about physics anyway, and K series stars are reflected/enhanced light from a troll civilization located within 500 light years or something. Perhaps the K series stars are reflectors for a nearby G series civilization.

In that case maybe the ratio of G/K reflects some kind of galactic intelligence level of average paranoia.

Or for that matter vice versa. Perhaps we're the odd men out and most galactic civilizations are K series and find it hilarious to "frame" innocent G series stars.

I suppose extremely detailed planet searches will be performed on these interesting stars, regardless of natural or SETI cause the results are likely worthwhile.

</comment></comment></comment></comment><comment><USER9> SETI@home has responded to this [1]. TL;DR don't get your hopes up. However, Breakthrough Listen will look at the stars using their Automated Planet Finder [2]

\- [1] [http://setiathome.berkeley.edu/forum_thread.php?id=80378](http://setiathome.berkeley.edu/forum_thread.php?id=80378)

\- [2] (PDF) [https://seti.berkeley.edu/bl_sdss_seti_2016.pdf](https://seti.berkeley.edu/bl_sdss_seti_2016.pdf)

</comment><comment><USER10> I have seen many papers on arxiv that are typeset without latex turned out to be a shoddy research work. I don't know there might be a correlation.

there is a response from berkeley SETI: [https://seti.berkeley.edu/bl_sdss_seti_2016.pdf](https://seti.berkeley.edu/bl_sdss_seti_2016.pdf)

</comment><comment><USER11> Seems like they jumped really quickly to 'aliens' as an explanation and I don't find it particularly convincing.

<comment><USER6> The end of the abstract is funny:

> Although unlikely, there is also a possibility that the signals are due to > highly peculiar chemical compositions in a small fraction of galactic halo > stars.

Talk about "unlikely"...</comment></comment>


Real-time visualization of DDoS attacks - <AUTHOR> http://map.ipviking.com/?_ga=1.147868727.1801181418.1403702171

<comment><USER2> This would look great on a big screen in an ops center. Not taking anything away from DAEDALUS though - and glad to see it mentioned, it has that slick Ghost in the Shell interface.

</comment><comment><USER3> This is really cool. In the same space (ie real-time visualization of DDoS attacks) is DAEDALUS-VIZ, although I don't know if/where it was implemented for people to watch.

</comment><comment><USER4> While this looks cool, what is a practical application of this?</comment>


Ocelot: The story of a torrent tracker - <AUTHOR> I took this directly from a newspost on what.cd, and I have no association with anything written here.  Just thought HN would find it interesting.
What.CD is a private tracker. Thus, the entire site, staff, and community all revolve around a common piece of software - the tracker backend. Complementing the site frontend, which you're looking at now, the tracker itself handles connections between peers.
With over five million peers, our tracker receives an average of 3,500 hits per second, although after a period of tracker downtime, load can spike up to past 12,000 hits per second. This means that, when your client announces, the tracker has 80 microseconds to search through its database of over 900,000 torrents and 5,000,000 peers, compute a response, and send it back to you. That's a lot of stress on a piece of software!
We anticipated this problem, of course, back before the site even started. That's why we elected to use what was then the fastest private tracker backend in the world - XBTT.
Lauded for its speed, XBTT handled the peers very well for the first few months of the site's existence. We brought on a developer - asm - whose job was to tune it and modify it as needed, and he was able to do that just fine - for a few months. However, asm was reluctant to make any major changes. When we asked why, his response was that XBTT's code was too weird, and that he was afraid he'd break something.
A bit surprised, we lead site developers peered into the bowels of XBTT for the first time, and we found that he was correct. XBTT's internal code worked fine in practice, but strange/outdated design decisions and the inclusion of thousands of lines of unnecessary code gave us worries about how well it would scale to a swarm of the size we had planned, as well as whether we'd be able to continue modifying it to our needs.
So a plan was formed. We would create a tracker of our own.
Late winter 2007
It made perfect sense. We were already replacing the outdated TBDev source with our own new Gazelle source, so why not replace XBTT with another piece of software as well? Make it fast, make the code pretty, give it a cool-sounding exotic animal name, and we'd be set. It couldn't possibly take very long - trackers are very simple pieces of software, after all. The only problem was that XBTT had scared asm into hiding, the other developers were all php developers (php is a language that is fast to write and slow to run) and we wanted the tracker coded in C++ (slow to write, fast to run). The solution was thus to outsource.
January 2008
Our first developer choice was a young developer called rootkit. Immensely intelligent, but perhaps not the greatest people person in the world, rootkit decided that he wanted to write the tracker in haskell instead. We weren't too excited to have the tracker written in a weird language that no one understood, but he promised that it'd be fast so we let him go at it. We don't think he ever wrote more than a hundred lines of it before he gave up and stepped down.
While we searched for a new developer, WhatMan decided to try an experiment - to see if a php tracker could outperform XBTT. He hacked away for a weekend and created Lioness - a beautiful little tracker, no doubt one of the fastest php trackers ever made. Unfortunately, it wasn't quite fast enough for our needs - upon testing, the swarm crushed our poor webserver, and we were forced to go back to XBTT.
By this time, XBTT was barely able to keep up with the load. The timeouts had already started, and we did whatever we could, but in the end, the only thing that really helped was when we moved to our new (then) ridiculously oversized server in Canada.
March - May 2008
Another developer had been found! The guy was smart, mature, well educated, fluent in C++, and seemingly very able. We told him what we needed, and he started coding. A month later, the new dev - lenrek - had created the first tracker to call itself Ocelot.
lenrek's ocelot looked promising. It was new, shiny, and multithreaded. We figured that our problems were solved, but when we tried it out, it exploded. It is still unclear exactly why, just that it happened. That ocelot was tweaked and some more tests were run, but we eventually gave up. lenrek's ocelot was basically shelved, and attention turned, for the next year, back to making XBTT handle its load properly.
Fortunately for us, lenrek stayed on as a developer - although his ocelot didn't succeed, he's responsible in a large part for making the site work as well as it does today.
June 2009 - February 2010
In the next year of stagnation, ocelot was never quite forgotten, but working on it was never very motivating - especially with only one tracker dev. So we raised the XBTT announce interval from 30 minutes to 35, then to 40, then to 45. In the meantime, the idea of ocelot waited until we found someone to revitalize it. In June 2009, FZeroX found such a person - rconan.
rconan was incredibly intelligent, and came up with a plan for what everyone was pretty sure was going to be the most awesome tracker ever. High performance event queues, hashmaps, all that cool stuff. We outsourced the project to him, he started coding, and initial progress was very rapid.
Two hundred changes and additions to rconan's new ocelot were made between the months of August and October. Before we knew it, the new ocelot was all but finished - 4,000 lines of divine C++ code, with just "a few" bugs and features left to code. And then, rconan's real life started to get busier.
A couple of changes were made in November, a couple in December, one in January, and a final flurry of activity took place in February. When we asked for progress updates, ocelot was still a few bugfixes and features away from being ready for production, but no changes were ever made after February. As none of our in-house developers had been closely following the development of the new ocelot, we were unable to take over, and simply hoped that rconan's real-life obligations would clear up and he'd have the time to finish it.
In the meantime, we had raised XBTT's announce interval to the highest point we could justify - 47 minutes - and it was still timing out so often it became a joke. In April 2010, we gave it its own server and started load balancing multiple instances of it - starting out with 2 XBTTs, and then 3, and then 4. This gave us some breathing room, but not for long.
April - May 2010
At on point, A9 and oorza were arguing about java performance. A9 had the brilliant idea of daring oorza to write a high performance tracker in java, and work began on shadowolf. oorza proclaimed shadowolf "almost completely done" on May 12th, save a few outstanding bugs. We checked in on his progress at the end of August, and he was rewriting the entire plugin architecture, and considering using hadoop to store peers. We're unsure about shadowolf's current status.
August-September 2010
No updates had been made to ocelot in eight months, and rconan was nowhere to be found. The future of shadowolf was unclear. When a thread came up about ocelot in the forums, the staff were forced to admit that development on it had ceased, and that no update was liable to take place in the near future. It was a hard post to write, considering how the timeouts had become so bad that the joke wasn't funny anymore. Users would sometimes have to wait hours for the tracker to let them download things, stats were being lost left and right, and we were out of hardware to throw at the problem. Something had to be done.
Enter WhatMan. Having previously stayed out of the C++ tracker development arena due to a lack of confidence with his high-performance C++ coding skills, WhatMan was confused with as to why everyone was creating 4000+ line of code behemoths when trackers are, in reality, extremely simple pieces of software. So he lifted some key design choices from rconan's ocelot, created the rest of the design himself, and spent the last week of August hacking away at a brand new ocelot.
On September 1st, ocelot was ready for performance testing. We replaced one xbtt instance with it, and it scaled. So we replaced two, and it scaled. We tweaked it a bit, and then replaced the third and fourth instances, tweaked it a bit more, and replaced the load balancer. What four XBTT instances and a load balancer were failing to handle before, was now being handled by one, singlethreaded instance of the latest ocelot.
Then we pushed it harder - we lowered the announce interval to 40 minutes, and then to 30, and it scaled. Then we lowered it to 20 minutes, and linux broke before ocelot did. It was beautiful.
The dev team rejoiced, and banded together to add the remaining features and fix the remaining bugs. By September 3rd, ocelot was considered feature complete, and we let it run the entire swarm - one tracker for five million peers, at a 30 minute announce interval.
September 2010 - Now
Since then, ocelot's been purring along. It uses up 20%-30% of one CPU core, and 3GB of RAM - for comparison, our four XBTT instances used the same amount of RAM in total, and 50%-100% of a core each. It's 1547 lines of code long in total, which will be open-sourced at some point. The dev team has added the occasional bugfix, and there may be some bugs yet to be discovered, but our tracker is now more stable than it's been since we started. After over two and a half years, ocelot's journey to creation is finally finished. <comment><USER2> Interesting story. Especially how often they tried to develop a new tracker. Any more insights why they failed so often?

Another already opensourced torrent tracker is opentracker <http://erdgeist.org/arts/software/opentracker/>. Its written in c and was developed because other trackers were slow or needed much resources. After some time piratebay started to use opentracker because it was much faster then the other trackers.

There was also a great talk[1] (German) at the 24C3 about the development of opentracker and some nice insider stories about running a big torrent tacker like getting a call from the provider "you are under a ddos attack.." "aeh no, thats normal and the load on the server is really low" (they had to change the hosting company ;0)

[1] [http://dewy.fem.tu-ilmenau.de/CCC/24C3/mp4/24c3-2355-de- trac...](http://dewy.fem.tu-ilmenau.de/CCC/24C3/mp4/24c3-2355-de- tracker_fahrn-COMPATIBLE.mp4)

<comment><USER3> I have a little experience in designing software for HPC that, for the most part, is quite a bit more complicated than a BT tracker. Here's something I found on the opentracker website:

 _All technologies to implement this are around for more than twenty years. Still most implementations suck performancewise._

I have a feeling that mediocre programmers (or programmers who really don't know as much about systems as they think they do) are to blame here :(.

Edit: A little more detail.

Opentracker is built by a C programmer who knows his stuff. He knows that disk access in a app like this would be suicide and designed around that. Advantage #1.

Opentracker uses libowfat which looks to be written by another good systems programmer with an eye for clean design. He has also had a quite a bit of time to perfect his implementation. Advantage #2

Libowfat is inspired and partially architected using libdjb written by Dan Bernstein (a phenomenal old school systems developer with a long track record). His design models have been at work for years and years. Bernstein is truly a 'legend.' Advantage #3

Short answer: same as always; smart people doing smart things :).

<comment><USER4> Thanks for the pointer to libowfat, looks quite interesting!

</comment></comment></comment><comment><USER5> > It was new, shiny, and multithreaded

 _sigh_ , when will people learn about asynchronous I/O.

It would be interesting to see if something like this could be implemented in a programming language that has relatively "slow" virtual machines (e.g. Ruby) but base it on a fast event-processing library (e.g. Eventmachine). The tracker doesn't do a lot computation. It's mostly I/O, isn't it?

Another interesting choice would be node.js. A framework that seems to be optimized for that kind of architecture. A bit of caching and a scalable backend (e.g. Riak) would be a nice combination...

<comment><USER6> I dare you... :)

</comment></comment><comment><USER7> "A9 had the brilliant idea of daring oorza to write a high performance tracker in java..."

This can, in fact, be done. Pando's [X] managed, torrent-like p2p platform has a solid, fast, Java-based tracker component.

X <http://www.pandonetworks.com></comment>


Teach Programming to become a better programmer - <AUTHOR> https://www.zeroequalsfalse.press/2018/06/10/teach/ <comment> kyle-rb >What do they know? They know real world. So when explaining something like for example a Superclass, you can use something like a vehicle...

This is good up to a point, and obviously it makes sense for absolute beginners. But eventually, when you understand programming, and just need to learn a new thing, it makes more sense to frame it in terms of actual use cases. I tried to read an explanation of JavaScript promises that used Shake Shack as an analogy and I think there were too many levels of indirection to understand it. Meanwhile, there's a Google developers post that explains it using image loading and that one clicked pretty much right away.

<comment><USER2> As a child (circa easly 2000s) I was immensely confused by the analogies that online guides used to explain OOP. I ended up so confused that I just gave up for many years until a wonderful professor explained it to us in plain, concrete language.

Analogies and use cases can help demonstrate _why_ something is useful, but can also obfuscate concepts.

<comment><USER3> I had almost exactly the (almost the exact?) same experience.

I was 12 when I picked up a _" Head First Java"_ at the library. The first chapters on for loops and variables were a breeze, but after a few more the book started a new program of loosely analogizing various function specifiers to real-world ontologies; all against the background of a writing style that emphasized that programmers can also write (and poorly photoshop) in a "WILD & ZANY STYLE THE KIDS WILL LOVE'. Yes, I'm starting to remember the trauma now: "Vehicles and Cars" or 1-Stripe Zebras vs Zebras-with-many stripes vs a Zebra with a stripes attribute...

I had no problem with a for loop to print _" FUGAZI SUX"_ 99 times, but the book wasn't communicating how these concepts were important to making a nontrivial program in Java; which I desperately wanted to do so badly.

A bit later, I downloaded a book about writing computer exploits, which was very basic and very direct. Strangely, dealing with computers at this extremely basic level of stored instruction pointers, buffer overflows and assembly language actually let me gain the skills required to be an "actual programmer".

<comment><USER4> > Strangely, dealing with computers at this extremely basic level of stored > instruction pointers, buffer overflows and assembly language actually let me > gain the skills required to be an "actual programmer".

There is nothing strange about that. People learn in different ways. For me the Head First books were a great alternative to the scores of dry "here is fact 1. And here is proof for fact 1. Here is fact 2. Here is proof for fact 2." books, which bored me to death and didn't help me with learning.

</comment></comment></comment></comment><comment><USER5> I'd advise people to not teach if they don't understand the source material very well, it can lead to spread of misconceptions which can make the concepts more confusing for the students rather than less. I feel this is often left out of these discussions.

You can always pretend to teach yourself to navigate the concepts though, when learning the first time yourself.

<comment><USER6> I've found that when a developer on my team is tasked with explaining something to another team member, they themselves get a much better grasp of the topic.

When we are doing work we often do "what works" to complete the job. Somehow, becoming responsible for someone else's knowledge forces some people to understand their own limitations.

<comment><USER7> > I've found that when a developer on my team is tasked with explaining > something to another team member, they themselves get a much better grasp of > the topic.

Tightly related, rubber duck debugging: [https://en.wikipedia.org/wiki/Rubber_duck_debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging)

</comment></comment></comment><comment><USER8> In general, sure, that sounds like a great idea.

As for the actual linked website, [https://www.virtualprogrammingtutor.com/](https://www.virtualprogrammingtutor.com/), it's highly unclear what the deal is. Are the people requesting tutoring going to pay for this? Do the tutors get paid?

Teaching programming to become a better programmer is one thing, teaching programming for free so that someone else can make money is a another thing.

<comment><USER9> I do some mentoring on Codementor.io from time to time. Scammiest thing I've seen so far: program in Africa, teaching underprivileged to code. I was willing to mentor not for free, but at about 1/3 of my rate as I was on-board with what I thought the mission was. Then they asked me to sign an NDA... turns out the org was having the kids do client work. I noped out of that.

<comment><USER10> Did you come across this on Codementor?

<comment><USER9> Yes

</comment></comment></comment></comment><comment><USER11> Biggest issue I continuously encounter with new engineers is reinventing the mistakes of the past due not understanding the history of engineering and in turn what criteria we measure the quality of a decision on. Does this design take us closer to an over arching engineering ideal or farther a way?

The only course I've found is this one that starts from square one and gives new engineers this context is this: [https://www.udacity.com/course/software- development-process-...](https://www.udacity.com/course/software-development- process--ud805)

It would be great if there was more material online and we systematically teach new engineers history and context in addition to the nuts and bolts of making a program.

<comment><USER12> I'm interestied in this context. Thanks for posting it, of only not to plug the holes that my bachelor & master degree left me.

</comment></comment><comment><USER13> If you don't consider yourself talented, but you make it a profession, you can make it work and become successful, but if you have the talent, and you aren't a professional, then there's nothing you can do and everything will end in failure.

I've learned that lesson the hard way I think. I read the Pragmatic Programmer early in my career but I don't think I understood it very well.

</comment><comment><USER14> Anecdotally, I can say that I don't think I've ever been more sure of the material I've learned than when I was serving as a TA/Tutor for a computer science class at my college.

</comment><comment><USER15> In the first 4 months of 2018, I taught intermediate-to-advanced Python to about 2500 working engineers around the world. This was through a 30-hour series of online trainings, repeated once or twice each month.

It absolutely made me a better developer. Some comments:

* Since I don't teach beginners, some of the questions I get are really hard. As in, someone who's good enough at writing software they've been paid to do it for many years will encounter some hard problem, bang their head against a wall with it for days or weeks... and then ask me about it live during the Q&A.

* If I make some claim during class that is not accurate, the students - who, again, are all professional engineers in the work force - will eat me alive. The early classes quickly dispelled a lot of incorrect knowledge I didn't realize I had. (If I were teaching something like art or politics, maybe I could sometimes BS my way through something... but not coding.)

* Toy code sucks. I quickly figured out it is 10,000% better to have a realistic example that might actually exist in a production code base somewhere, for all sorts of reasons. This is also 10,000% harder to do well, for the instructor.

* We all have certain mental models and even beliefs that have been "installed" in our thinking from our previous coding experiences. A big part of my job is to quickly figure out what lens you're using to view coding reality (e.g. maybe you're a Java expat, and tend to think in terms of its type system); pace that reality so I don't lose you; and gently drag you into a very unfamiliar way of thinking, using the different metaphors required to reason about the new language/technology. Oh, I have to do it for 150 people from two dozen different countries all at the same time.

* Biggest surprise: what's been more useful than anything in helping me become better as a trainer: studying psychology and hypnosis. (Lots of subtle hints in how this applies in the previous item.)

<comment><USER16> > * If I make some claim during class that is not accurate, the students - > who, again, are all professional engineers in the work force - will eat me > alive.

This is interesting. I imagine that in high-level training for any industry this could happen. I'd personally try to let my students know that I'm not an all-knowing god and ask them to correct me if they noticed something I said was wrong, and I'd be happy learning something new. Maybe this is what you meant, but were you ever met with hostility or animosity because of this?

Also, what, in general, is intermediate-to-advanced Python?

<comment><USER15> No hostility ever, no, because (a) I freely acknowledge I don't know everything, and (b) I'll not hesitate to say if I don't know something or I'm not sure (or become unsure). People are of course really understanding and good-natured about it. "Eat me alive" is an overstatement; better to say they won't let it slide.

> Also, what, in general, is intermediate-to-advanced Python?

Basically the kinds of topics covered in my Python book, which I'll plug here without shame:

[http://amazon.com/d/0692878971](http://amazon.com/d/0692878971)

It's either intermediate or advanced, depending on your perspective.

</comment></comment></comment><comment><USER17> This has been so true for myself and many of our instructors at Fullstack Academy. There are so many cool ideas in programming that you can get by without - but once you start teaching it forces you to truly wrestle with those ideas. Definitely makes you a stronger programmer on the other side.

<comment><USER18> What are some of those cool ideas?

</comment></comment><comment><USER19> Thanks for the article -- especially agree with the "Lead and take the charge." I feel that's very important if you expect to learn from mentoring.

Shameless plug but I wrote a Medium article about what I learned from mentoring an intern last summer and what people can get out of it. I'm mentoring another intern this summer and it's really great working with different people and how they learn in different ways.

[https://medium.com/@augburto/the-menternship-why- mentoring-i...](https://medium.com/@augburto/the-menternship-why-mentoring- isnt-a-chore-54c04e75335f)

</comment><comment><USER20> I thought I was a pretty hot Pascal programmer in grad school. Then, for a period of time, I was tasked with teaching Pascal to professional programmers and engineers throughout Texas Instruments. I quickly discovered that there were aspects of the language (even in a language as simple as Pascal) that I found difficult to explain because I didn't fully understand them. Getting to teach the subject multiple times and each time making the presentation clearer made me understand the language, it's limitations, and effective use much better.

</comment><comment><USER21> let me add few things...

\- keep telling pupils the goods (of becoming a pro-gram-mer), AND telling them the bads. One at a time, some needs repeating often. Like the sky moments when u see someone using your stuff and liking it. Or the multi-shizophrenia that backs that achievement :/ They should know the whole truth, and decide - would they sustain all the pluses and the minuses, or such a vocation/devotion is not for them.

\- teaching/mentoring, esp. around my place, isn't much $$$ rewarding.. if at all. More, you can be considered a nuisanse/"wtf" \- when the common thinking is "give me monie/solutions, dont give me brains".. Sadly.

\- i do teach people, quite a few years, but by working with them. Not by lecturing.. Lecturing works en masse but is veeery short-term/shallow. (example: from 50+ ppl i taught python-courses in last 2-3 years, various levels, ~6 became programmers and/or went using it.. half of them with further mentoring. From ~20-25 ppl i have worked-with and mentored in last ~15 years, all became pros... some better than me.)

\- It is a very deep investment.. maybe as more for the teacher/mentor as for the pupil/mentee.

have fun www.svilendobrev.com

</comment><comment><USER22> I've done this on IRC since the late 90s and I think it benefited me greatly, but you should see the blank stares I get when I mention this in interviews. Best just to forget mentioning "IRC" in general.

EDIT: "in interviews" to put things in real terms

<comment><USER23> Yeah I spent hours in linux IRCs helping out new users, and it helped cement my understanding.

It's funny looking back. Sometimes you can do something that seems engaging at the moment, but turns out to have been a massive waste of time. Yet hanging out in a chat room for hours on end felt like a waste of time in the moment but looking back it was very valuable to me.

</comment></comment><comment><USER24> I said the same thing back in the day... Nothing teaches the nuance more than trying to explain something and being wrong in front of 20 people.. you make sure you fully understand it so it doesn't happen again.

<comment><USER25> It's embarrassing at first, but it can be turned into a learning experience for everyone. It can foster a more engaged, collaborative classroom when an instructor admits when he's wrong and graciously thanks students for improving their own knowledge. That said, the instructor should have the strongest grasp of the material.

</comment></comment><comment><USER25> If you're in New York City or the San Francisco Bay Area, ScriptEd ([https://scripted.org/volunteer/](https://scripted.org/volunteer/)) offers opportunities to teach programming to students at under-resourced high schools. It's especially rewarding because these are students who are least likely to be exposed to this material in their normal curriculum. If your employer is OK with you taking half days twice a week to volunteer, then I strongly recommend it. It's a unique growth opportunity.

</comment><comment><USER26> The "Lead and Take Charge" point is an interesting one, which I don't entirely agree with (if I'm reading it correctly).

I mentor weekly (codebar) and sometimes find myself not knowing the answer to a question. When that happens, I'm honest about my position, and then show the mentee how I go about figuring out the answer. After a couple of times I get them to suggest an approach to answering it. By doing this, I cede control. The point, after all, it to make myself redundant as a mentor!

</comment><comment><USER27> This is what I do, I teach stuff to become better at it because trying to explain it to someone else makes you think of it as a designer where you have to reframe.

Reframing opens up the potential to understand both as an end user and as a manipulator(creator).

Once you see both sides, it becomes clearer.

</comment><comment><USER28> Good advice for nearly anything.

Whatever it is, teach it to someone else if you want to understand it better yourself.

</comment><comment><USER29> The easiest way to "teach" programming right now is to watch beginners programming on twitch and offer advice when you can. Trying to pair remotely through chat also imrpoves your pair programming skills.

Of course you could just write blog posts instead Kappa

</comment><comment><USER30> There is not question that teaching Python to beginners has made me appreciate various aspects of the language better.

For one how little need is there for map,reduce,filter in Python when you have list comprehensions and generators .

Still trying to find a use for coroutines though.

</comment><comment><USER31> "Those who know how to do - do, those who don't - teach. Those who can't even teach - manage".

Ok this is not very accurate but still amusing...

<comment><USER32> Should be "those who did - teach".

</comment></comment><comment><USER33> Maybe I'm the wrong audience for this (I have degrees in CS and Education and have worked in both fields) but this seems very simple/rudimentary and for the most part, doesn't really seem useful. Feels more like an ad for the link at the end.

"if you can't do then teach! ;)" Maybe the winking face was meant to indicate that this is tongue-in-cheek but nothing else in the article really serves to support that. I dislike this phrase in general.

Each section seemed too cursory to provide any meaningful insight. As a teacher, I'm used to having people with less expertise offer me advice like "Use real world examples if you want to be effective." So, uh, use the vehicle, car, truck, etc... analogy when discussing superclasses and subclasses. Okay. Can you provide something else that's not so superficial? And calling words like "polymorphism" mumbo jumbo doesn't really help either. It's domain specific language that you should introduce eventually while making connections (both to other content in the domain and real world phenomena). Of course using those words without sufficiently explaining them isn't enough but shying away from key vocabulary because you underestimate your student isn't the best policy either.

"So if someone is not getting what you're saying, try rephrasing your words and approach it like it's a challenge on your end, not theirs." I think this is a good point and could be insightful for people who haven't taught before. Anyone that engages in teaching should hopefully realize it is a skill that takes effort, practice and reflection to hone (like any skill). You won't be perfect from the beginning. Assume your students are trying their best to understand and you are both trying to work together to build the connections needed to reach understanding. But if you're going into this thinking teaching is just a thing people do and your goal is to become a better programmer, I think there are more efficient ways to achieve that. You must be willing to put the time and energy into working on your teaching before you start seeing the benefits.

"it must be clear who is leading the way." Hmm... Definitely disagree with this. In the beginning I'm leading and directing but I'm trying to build skills, confidence and motivation such that control is slowly shifted to the learner (Student-led instruction is a big buzzword (buzzphrase?) in the edu world). I want my students to become independent so that whenever they leave me they can continue learning on their own. Going from having a boss/teacher that always takes charge to the "real world" of learning and doing all on your own can be disorienting. Let the student take the reigns so they get experience making decisions on their own while you're still there to offer guidance.

Sorry if this came across as harsh, I hope it can be taken as constructive criticism as opposed to me just being mean spirited. I definitely appreciate the subject of teaching popping up on hn.

</comment><comment><USER34> An even better way is to program, program and program some more.

Doing ( creating software ) > teaching/explaining > doing nothing.

Nothing beats solving problems yourself.

<comment><USER35> Doing is not strictly better than teaching. You can do a lot without understanding what's really happening. You can't get away with that when you teach.

<comment><USER36> I agree, having another question your assumptions and explanations forces you to learn it deeper.</comment></comment></comment>


Effective Go - <AUTHOR> http://golang.org/doc/effective_go.html <comment><USER2> I have been tinkering with Go for a couple months and I've been so impressed with it I'm about to start a real production server using it. It has all the low-level functionality of C with some very useful features added, like garbage collection, string manipulation, new data types like slices and channels, and of course threading.

The main downside is that there are not a lot of libraries available. If you want to use the language you will find yourself using 3rd party wrappers off github of unknown quality, and you will probably have to wrap some C libraries yourself, because no one else has.

Also, both the garbage collection and the goroutine scheduler could use some work. Like most other garbage-collected languages, Go's GC has to stop all threads in the program while it does its work, causing milliseconds of lag. This makes the language unsuitable for realtime work like a fast-paced video game.

The goroutine scheduler works using a fixed-size thread pool. You have to tell it how many threads to use - by default programs are single-threaded. It has no ability to lower the thread count when the system is under heavy load, or to raise the thread count when most threads are unproductively waiting on network IO.

Despite these minor problems it is amazingly full-featured for a compiled language, and amazingly fast for a full-featured language. They are actively working on improving the garbage collection and they plan to improve the thread scheduler.

<comment><USER3> I will just note that improvements to the GC and scheduler and other compiler optimizations are already implemented and will be part of Go 1.1

Also, the Go stdlib is very rich and covers lots of stuff, I have rarely found need for bindings to C libs unless it is OpenGL.

Which brings me to the point of games, there are already a couple of games using Go, the GC pauses are not as big of an issue because the GC is good enough (it is parallel) and in Go is easy to avoid generating garbage.

<comment><USER4> Questions for those more versed in Go's GC than I:

1) Let's say you want to do everything you can to avoid generating garbage. What would some those techniques be?

2) There is no delete function is there (for memory deallocation, not hashmap key removal)?

3) Is it possible to eliminate all garbage, and if so could you prevent the GC from starting up at all?

Possible existing answers that are a bit above my understanding (C# and Python spoil me):

<http://news.ycombinator.com/item?id=4231048>

<http://blog.golang.org/2011/06/profiling-go-programs.html>

[https://groups.google.com/forum/?hl=fr&fromgroups#!topic...](https://groups.google.com/forum/?hl=fr&fromgroups#!topic/golang- nuts/Ir7ZrKLddTU)

</comment></comment></comment><comment><USER5> Is there some reason documentation on the Golang website has 57 upvotes?

<comment><USER6> If I had to guess, it's because people are quite excited about the language and they're interested in giving it some visibility. There's always lots of new technologies, but very few gain wide adoption.

</comment></comment><comment><USER7> Any idea why Go uses tabs for formatting? (A google search didn't provide the answer but did suggest I may want to find out why God does!)

About the only good pro-tab stance I have seen is that it allows the viewer to choose a level they prefer, but I would expect consistency would be far better.

<comment><USER8> That was actually one of the questions asked during the "Meet the Go team" talk at Google I/O. They joke around for a bit, but they end up giving some solid arguments.

[http://www.youtube.com/watch?v=sln- gJaURzk&feature=playe...](http://www.youtube.com/watch?v=sln- gJaURzk&feature=player_detailpage#t=1735s)

Edit: If you're curious/interested in Go, it's worth watching the whole talk.

<comment><USER7> The answer given was that individuals can then choose how many spaces they want their tabstops set to, and this was mostly an accident not formal thought out design. (I didn't see any other arguments given.) gofmt itself is of course a very good idea.

I have been following Go along the years, but think they made a big mistake with exceptions. In particular you have to manually write the code from where an issue happens all the way to where it is handled. Exceptions as done in other languages isn't the exact pattern that has to be followed - it is the writing of the boilerplate code that bugs me. Heck they could do something as simple as if the error value returned is not used in any way then an automatic 'return ...vals..., error' is inserted after the call.

<comment><USER4> I'm curious if you have used panic/recover to see if it fills the perceived void. (I'm not saying they do, I don't know)

<https://code.google.com/p/go-wiki/wiki/PanicAndRecover>

<http://blog.golang.org/2010/08/defer-panic-and-recover.html>

<http://dave.cheney.net/why-go-gets-exceptions-right>

<comment><USER7> Thanks for the links, and panic is the usual retort. My problem is with the boilerplate between methods. If A calls B calls C calls D calls E which can have issues that A wants to handle (eg try a different IP address) then all the intermediary functions will need code like:

       foo,bar,err=callX(...)
       if err!=nil:
           return _,_,err

It is the last two lines of boilerplate that need to be present for virtually every call that makes me uncomfortable. Developers will start forgetting or not being diligent which causes problems. Also I think (but don't know) that by the time A gets an Error it won't know what the stack trace is for the original Error. (The stack traces are extremely useful for logging and analytics not for program behaviour.)

Needing to write the boilerplate means it is left out. For example look at all the hello world examples. Note how they all ignore any errors from the println. C has exactly the same problem, and I'm disappointed that Go is perpetuating this problem.

</comment></comment></comment></comment></comment><comment><USER9> The Go language seems to have some substantial documentation, which is great. Though, throughout, the code snippets would look better with some syntax highlighting.</comment>


Help me rename "Lifestyle Business" - <AUTHOR> http://redeye.firstround.com/2009/07/we-need-a-new-name-for-this.html

<comment><USER2> I'd have the opposite take on the title "lifestyle business". The opposite is really the "get rich or die trying" business. The opposite are the businesses that can only survive as long as they keep coming out with some new novelty until they're bought without necessarily creating a sound business.

Lifestyle business means that you have your priorities right. The purpose of business and money is making life easier and nicer. Life's purpose isn't business and money. The problem is that we put people like Mark Cuban on a pedestal for creating something that couldn't make money and didn't create much value simply because someone else was stupid enough to pay billions for it in a frenzy. At the same time, we don't have a lot of respect for people like the restaurant owner who does a consistent good job because what he does can never have the "infini-scale" of large web projects and get bought for billions.

Of course, as we've seen, the "infini-scale" almost never happens. Really, what company that was purchased in all the .com land rushes has made the owner much money? Not broadcast.com, not YouTube, not Geocities, not AOL, not FeedBurner, not Jaiku, not Dodgeball. . . But all of them were acquired for tons of money. They played "get rich or die trying" and got rich while making nothing that lasts up to that measure.

Lifestyle businesses aren't about who works harder. It's about creating known value rather than the latest fad. It's about giving customers something good at a fair price rather than trying to corner the market, exercise the synergies, actualize the growth potential, or whatever other marketing speak one would use to get a large, scared player to buy you when you have no profit potential. Lifestyle businesses are about humbly giving people something good and knowing that you're making a positive impact on their lives. Maybe you aren't "game changing", but people appreciate a good business.

<comment><USER3> Before Broadcast.com, Mark Cuban had multiple profitable businesses and a hedge fund.

People often put him on a pedestal or tear him down because they're misinformed.

</comment></comment><comment><USER4> I vote for "Business"

<comment><USER5> Replace "lifestyle business" with "business" - because that's what they are.

Instead, come up with a new name for the ones that VC's like to invest in.

<comment><USER6> venture?

</comment></comment></comment><comment><USER7> +1 to this.

I like the point of that "Miles" made in the comments: that there really is such a thing as a lifestyle business, but there needs to be a new term for businesses too small to interest VCs.

A "lifestyle business" is something that makes you enough money to get by, perhaps somewhat passively.

But no one should call 37signals a "lifestyle business" -- they are a small company with millions of dollars in revenue. But VCs probably would not have been interested in them because they didn't plan to take over the world.

Just wondering...what are the options for funding a business that isn't VC sized but could be successful in its niche? Bootstrapping? SBA loans?

<comment><USER8> We're going the bootstap + day job route. It's very hard, but we spend our time working on the project instead of worrying about funding.

However, I'm also very curious about SBA loans, and other loan financing.

<comment><USER9> I've been working the SBA loan route for a while now, and I'm preparing to post a summary of my experiences to HN. If anyone out there has also tried to get SBA-backed loans for a startup, holler and maybe we'll co-write some tips for other entrepreneurs.

</comment></comment></comment><comment><USER10> I put in my $0.02 with "Freestanding Business"

</comment><comment><USER8> I love the term "Lifestyle Entrepreneur" and I wear it with pride. There was a time when I thought it was all about raising investment money. Then I realized that such a prospect was completely outside of reality, and furthermore, I didn't need the money. Then I just hunkered down and got to work.

Feel free to rename it if you want, but I'll stick with the original.

<comment><USER11> i agree. i don't find the term lifestyle business demeaning.

i've had some lifestyle businesses in the past that have done really well, and frankly, when you have a _really_ successful lifestyle business, if someone treats you condescendingly, sitting at the beach drinking pina coladas at 11am on a weekday is a great remedy.

</comment></comment><comment><USER12> There's nothing inherently 'demeaning' about the term 'lifestyle business' -- except that in the context of people who are seeking something more, it implies something less.

Picking a new name will shift the implication. See "euphemism treadmill":

[http://en.wikipedia.org/wiki/Euphemism#The_.22euphemism_trea...](http://en.wikipedia.org/wiki/Euphemism#The_.22euphemism_treadmill.22)

Whatever new term is picked, no matter how initially flattering, will -- when repeatedly used in the same contexts -- eventually adopt the same connotations of 'not good enough for bigtime purposes'.

<comment><USER6> I agree partially. So long as the word means 'that thing VCs won't invest in,' it's demeaning.

But lifestyle business is inherently demeaning. It implies a goal of cutting back on stress, hard work, long hours etc. A retirement business. A B&B.

Since most of those it is applied to (in this context) do not have these goals, it is insulting. Like calling a punk rocker adorable.

The thing is that it's not what VC's won't invest in that needs a name, it's what they do invest in that needs one. For one thing, an exit plan is something the majority of businesses do not have when they start.

</comment></comment><comment><USER13> I like the name "business" :-) But, I do think joshk is right that "lifestyle business" is a bit of a demeaning term nowadays. My submissions are "pasta profitable" and "leanstrapped"; latter seems to hit a nerve with people. Feel free to vote em up or down.

</comment><comment><USER14> Indepenture - independent venture

</comment><comment><USER15> Self Employment.

<comment><USER4> ?? My non VC funded company has 20 employees...

<comment><USER15> In that case, I'd go with your suggestion: "Business".

</comment></comment></comment><comment><USER16> I have always preferred "Lifestyle" to "Trojan." Wait, what were we talking about?</comment>


A Cautionary Tale for (Startup) Sales People - <AUTHOR>

I work for a very large company (65K+ employees, thousands of developers). Our IT department has a $1 Billion+ per year budget). The industry is financial/insurance, so we have a lot of red-tape when it comes to purchasing things.
I recently wanted to get some development software from a company that we have never purchased from before. The first step in the process is to get a Non-Disclosure Agreement (NDA) in place, followed by a review of their EULA.
After our purchasing area sent the NDA to the software company, one of the salespeople wrote back and told us that they didn't want to use our NDA, they aren't going to modify theirs and that we should go through one of their resellers that we already had an NDA in place with. Fine.
Then purchasing starts to take a look at the EULA. It has some terms that are never going to pass muster with our legal department; for example: they can use our name in advertising. No one is allowed to use our name for advertising. Not IBM, not Oracle, not Microsoft, no one (all three of those companies signed our NDA). So our purchasing department decided that they don't want to deal with them to get the EULA changed since they wouldn't even work with us on a simple NDA.
We are going to purchase a competitor's product - there is no open source equivalent.
Why does this matter? Once everything was in place, it would have been really easy for someone else in my company to purchase more software from them. And we spend a lot on software.
Just because someone at this little company didn't want to take the time to research who they were dealing with and gave some attitude to a purchasing department, they will likely never have a chance here again.
If you're a startup, you might want to do some research about a company that comes knocking at your door and seems to be a bit of a pain in the ass. If they have a $1 Billion dollar IT budget (or even a little less than that), it might be worth it. <comment><USER2> Sales people have it tough in a startup environment. They can't go around acting cool, wearing shorts and slippers. Cause they are business and need to act like that. In a startup they need to act different especially with clients. If the client is interested in working with a startup, that's a big leap of faith they are taking. So the sales dep. need to adjust and accommodate the clients deamands and concern.</comment>