Computers are fast - <AUTHOR> http://jvns.ca/blog/2014/05/12/computers-are-fast/ <comment><USER3> I particularly enjoyed the writing style in this article, largely because of the extent that the author provided unverified and loose figures in the article - cputime distributions etc. My experience is usually people are extremely hesitant to publish any uninformed, fast, and incomplete conclusions despite them being, in my opinion, still extremely valuable. It may not be perfectly correct, but that small conclusion is still often much better than the practically non existent data on the situation I start off with and allows me to additionally read the article far faster than slowing down to make these minor fuzzy conclusions myself. There is this misconception that when writing you can do two things - you can tell a fact or you can say a false statement. In reality it is a gray gradient space, and when the reader starts off knowing nothing, that gray is many times superior. Anyways, awesome job, I really want to see more of this writing style in publications like personal blogs.

[In case it isn't clear, I'm referring to statements like "So I _think_ that means that it spends 32% of its time accessing RAM, and the other 68% of its time doing calculations.", and "So we've learned that cache misses can make your code 40 times slower." (comment made in the context of a single non- comprehensive datapoint)]

<comment><USER4> Agreed. At first, the writing style (too! many! exclamation! points! Are you Unidan or what?) made me think that the article wasn't serious. The fact that I immediately thought, "you're just going to be benchmarking your disk!" didn't help, either. But the author did take the disk performance into account, and the rest of the article was surprisingly interesting as well. It's a quick and dirty exposition for a quick and dirty suite of benchmarks.

<comment><USER5> I don't know, I love her enthusiasm.

<comment><USER6> Same here. I thought it helped to dispel the conception that only Very Serious People should be interested in this stuff.

</comment></comment></comment></comment><comment><USER7> I posted the following as a comment to the blog, I'll duplicate it here in case someone wants to discuss:

This program is so easy on the CPU that it should be entirely limited by memory bandwidth and the CPU should be pretty much idle. The theoretical upper limit ("speed of light") should be around 50 gigabytes per second for modern CPU and memory.

In order to get closer to the SOL figure, try adding hints for prefetching the data closer to the CPU. Use mmap and give the operating system hints to load the data from disk to memory using madvise and/or posix_fadvise. This should probably be done once per a big chunk (several megabytes) because the system calls are so expensive.

Then try to make sure that the data is as close to the CPU as possible, preferably in the first level of the cache hierarchy. This is done with prefetching instructions (the "streaming" part of SSE that everyone always forgets). For GCC/Clang, you could use __builtin_prefetch. This should be done for several cache lines ahead because the time to actually process the data should be next to nothing compared to fetching stuff from the caches.

Because this is limited on memory bandwidth, it should be possible to do some more computation for the same price. So while you're at it, you can compute the sum, the product, a CRC sum, a hash value (perhaps with several hash functions) at the same cost (if you count only time and exclude the power consumption of the CPU).

<comment><USER8> Yup, __builtin_prefetch certainly, if one wants to get it faster. (Compilers can't do this themselves, because they don't know how much they should prefetch ahead, and if you get that wrong it's worse than no prefetching.)

I am less sure about madvise. It seems to me default heuristics should work fine for this case, and as you said, system calls are expensive.

<comment><USER7> > I am less sure about madvise. It seems to me default heuristics should work > fine for this case, and as you said, system calls are expensive.

System calls are expensive but so are page faults or having to access the disk. If you can avoid page faults by using madvise to prefetch from disk to memory, it should be worth it. In particular, the first run with cold caches should be faster.

However, the operating system may be smart and realize that we're doing a sequential access and may speculatively read ahead and madvise calls would be time wasted.

The same happens with CPU caches too, the CPU internal prefetcher is pretty good in recognizing a sequential access and grabbing the next cache line in advance. A few naively placed __builtin_prefetches doesn't seem to help here (I just tried this out).

Prefetching hints work a lot better in non-sequential access patterns (linked lists, etc).

</comment></comment></comment><comment><USER9> Pretty naïve, I'm surprised to see it here. Not that this is pointless study, but it's pretty easy to guess up these numbers if you know about how long it takes to use a register, L1, L2, RAM, hard drive (and you should). And exactly how long it would take is task-specific question, because depends more on what optimization techniques can be used for the task and what cannot, so unless you are interested specifically in summation mod 256, this information isn't much of use, as "processing" is much broader than "adding moulo 256".

But it's nice that somewhere somebody else understood, that _computers are fast_. Seriously, no irony here. Because it's about time for people to realize, what disastrous world modern computing is. I mean, your home PC processes gigabytes of data in the matter of seconds, amount of computations (relative to its cost) it is capable of would drive some scientist 60 years ago crazy and it gets _wasted_. It's year 2014 and you _have to_ wait for your computer. It's so much faster than you, but you are waiting for it! What an irony! You don't even want to add up gigabyte of numbers, you want to close a tab in your browser or whatever, and there are quite a few processes running in the background that actually have to be running right now to do something useful, unfortunately OS doesn't know about that. Unneeded data cached in the RAM and you wait while OS fetches memory page from HDD. But, well, after 20 layers of abstraction it's pretty hard to do only useful computations, so you make your user wait to finish some computationally simple stuff.

About every time I write code I feel guilty.

<comment><USER10> I agree completely. Hardware has gotten _orders of magnitude_ faster, yet the experience, as a user, hasn't changed nearly that much. You'll probably find this comparison interesting: [http://hallicino.hubpages.com/hub/_86_Mac_Plus_Vs_07_AMD_Dua...](http://hallicino.hubpages.com/hub/_86_Mac_Plus_Vs_07_AMD_DualCore_You_Wont_Believe_Who_Wins)

I think the saying that programmer time is more expensive than machine time is, like the quote about premature optimisation, responsible for promoting an inherently wasteful culture in programming when people are taught to take them at face value; looking at it another way, power isn't free, and when machine time translates to _user_ time, then the situation definitely changes. I always keep in mind that users are using the software I create to _do work_ , and their time is just as valuable if not more so than my own, especially if there are more of them. To me, it's a question of balancing the tradeoffs --- it's not worth spending a day to optimise software that will save a few minutes across all its users over its lifetime, but it is very well worth it to spend a week to optimise something so that it may save a year or more of its users' time. Whenever a programmer complains about certain tools (e.g. compiler, IDE, etc.) being slow, I keep that in mind to mention the next time he/she flippantly dismisses a time-saving optimisation using the "my time is more expensive" excuse. Programmers are users too. :-)

<comment><USER11> Found this gem in the linked article: _Windows Vista demands enough real estate on your hard drive that you could easily fit 30,000 full-length novels into it._

A nitpick: a day of work, say six hours, is only 3600 minutes. If you can optimize some task to save a few minutes per user, it only takes a few thousand users to be worth it.

However, I think the worst optimizations to leave on the table are in an area many developer-types won't think about: usability. We can save much more of a user's time by creating simple, intuitive interfaces than we can checking cache misses (in most modern development).

<comment><USER12> > We can save much more of a user's time by creating simple, intuitive > interfaces than we can checking cache misses (in most modern development).

And at least for regularly-used software, you can save even more user time by not optimising for the first five minutes of usage but for the long-term usage. Keyboard shortcuts are a good example for this: They are mostly not simple and certainly not intuitive per se (why does Alt+Tab switch windows in particular?), yet once you know them, they do save a lot of time.

</comment></comment></comment></comment><comment><USER10> _I wrote a new version of bytesum_mmap.c [...]and it took about 20 seconds. So we've learned that cache misses can make your code 40 times slower_

What's being benchmarked here is not (the CPU's) cache misses, but a lot of other things, including the kernel's filesystem cache code, the page fault handler, and the prefetcher (both software and hardware). The prefetcher is what's making this so much faster than it would otherwise be if each one of those accesses were full cache misses. If only cache misses were _only_ 40 times slower, performance profiles would be very different than they are today!

Here are some interesting numbers on cache latencies in (not so) recent Intel CPUs:

[https://software.intel.com/en- us/forums/topic/287236](https://software.intel.com/en-us/forums/topic/287236)

 _I'm also kind of amazed by how fast C is._

For me, one of the points that this article seems to imply is that modern hardware can be extremely fast, but in our efforts to save "programmer time", we've sacrificed an order of magnitude or more of that.

<comment><USER13> > _For me, one of the points that this article seems to imply is that modern > hardware can be extremely fast, but in our efforts to save "programmer > time", we've sacrificed an order of magnitude or more of that._

Sounds like a good deal!

<comment><USER14> To who and in what situations? To businesses(hardware and software) sure, they get products out faster and are motivated to push new stuff out. To end users, not so much, because they wait more and their batteries drain faster. They also pay more for hardware to have a "good experience".

<comment><USER15> They also have an order of magnitude more software to choose from, which tends to drive cost of software down through competition (though I'll grant it that most free models we're stuck with today suck, and I wish paying at least $10 for good software was still a common thing.) More importantly, a lower barrier of entry to developing allows a much longer tail of niche applications to be produced, and perhaps even more important, experts and hobbyists from other domains can go and create software using all the knowledge from their "main" field.

</comment></comment></comment></comment><comment><USER16> Interesting investigation!

I had an experiment with getting the Rust compiler to vectorise things itself, and it seems LLVM does a pretty good job automatically, e.g. on my computer (x86-64), running `rustc -O bytesum.rs` optimises the core of the addition:

      fn inner(x: &[u8]) -> u8 {
          let mut s = 0;
          for b in x.iter() {
              s += *b;
          }
          s
      }

to

      .LBB0_6:
      	movdqa	%xmm1, %xmm2
      	movdqa	%xmm0, %xmm3
      	movdqu	-16(%rsi), %xmm0
      	movdqu	(%rsi), %xmm1
      	paddb	%xmm3, %xmm0
      	paddb	%xmm2, %xmm1
      	addq	$32, %rsi
      	addq	$-32, %rdi
      	jne	.LBB0_6

I can convince clang to automatically vectorize the inner loop in [1] to equivalent code (by passing -O3), but I can't seem to get GCC to do anything but a byte-by-byte tranversal.

[1]: [https://github.com/jvns/howcomputer/blob/master/bytesum.c](https://github.com/jvns/howcomputer/blob/master/bytesum.c)

<comment><USER17> GCC vectorizes the sum fine if the input is _unsigned bytes_ , cf [1]. My guess is some odd interaction between integer promotions and the backend.

[1] [http://goo.gl/B7KX1V](http://goo.gl/B7KX1V)

<comment><USER18> This link seems to be breaking the HN comments for this page. :)

<comment><USER16> It's a shortened link (because the true link is so long, as you discovered), maybe you have a browser extension that expands them?

<comment><USER18> Ah, you're right, I do (Tactical URL Expander for Chrome)! That'd sure explain it.

</comment></comment></comment></comment></comment><comment><USER19> I like the "free" style of the article. Here is another conclusion: In my professional life I have heard many, many excuses in the name of performance. "We don't need the third normal form, after all, normalized databases are less performant, because of the joins". Optimizing for performance should not mean to make it just as fast as it could possibly run, but to make it just fast enough.

Julia's article shows a good example for this. Of course, the goal appears to generate a feeling of what tends to make a program fast and slow and get a feeling for how slow it will be or how fast it can get; yet I'd like to point out that this...

[https://github.com/jvns/howcomputer/blob/master/bytesum_intr...](https://github.com/jvns/howcomputer/blob/master/bytesum_intrinsics.c)

... might be 0.1 Seconds faster than the original code when started as "already loaded into ram" which she claims runs at 0.6 seconds. Yet this last piece of code is way more complicated and hard to read. Code like this

Line 11: __m128i vk0 = _mm_set1_epi8(0);

might be idiomatic, fast and give you a great sense of mastery, but you can't even pronounce it and it it's purpose does not become clear in any way.

Writing the code this way may make it faster, but that makes it 1000x harder to maintain. I'd rather sacrifice 0.1 seconds running time and improve the development time by 3 days instead.

<comment><USER20> Depends if that 0.1 seconds is going to add up to a very significant amount. Obviously these are just tests but in a production system running 24/7 that 0.1 seconds per run is going to add up to a lot. The code might be ugly but that is when comments are most important.

<comment><USER21> Or it might add up to next to nothing, if a full run is eight hours. Or it might finish early and then be blocked waiting for some other part of the system.

The moral of "computers are fast" is that guessing about bottlenecks and twiddling with the lowest level of code is unlikely to help; you need to start at the top with a profiler, and start asking the questions "do we need to compute this at all?", "can we make it O(n log n) or better?", and "can we partition this to scale horizontally?"

<comment><USER22> Not only at the top, but with profiling a task that is relevant for the user. It is trivial to find some code that could be "speed up", but if it does not bring any value to the user, what is the point?

</comment></comment></comment></comment><comment><USER23> For an in-depth presentation on how we got to this point (cache misses dominating performance), there's an informative and interesting talk by Cliff Click called _A Crash Course in Modern Hardware_ : [http://www.infoq.com/presentations/click-crash-course- modern...](http://www.infoq.com/presentations/click-crash-course-modern- hardware)

The talk starts just after 4 minutes in.

</comment><comment><USER24> It's 1.08s on my computer for one line of Python, which is respectable:

      python2 -m timeit -v -n 1 -s "import numpy" "numpy.memmap('1_gb_file', mode='r').sum()"
      raw times: 1.08 1.09 1.08

<comment><USER25> Isn't a lot of numpy implemented in C?

<comment><USER24> Sure, but the point is that you can get some pretty nice speeds without writing any C yourself.

<comment><USER26> But only for operations that someone else has written the C code for you. If you come up with some new algorithm that cannot be reduced to operations already implemented in C, then you would need to write the fast C implementation yourself.

</comment></comment></comment></comment><comment><USER27> 1/4 second to plow through 1 GB of memory is certainly fast compared to some things (like a human reader), but it seems oddly slow relative to what a modern computer should be capable off. Sure, it's a lot faster than a human, but that's only 4 GB/s! A number of comments here have mentioned adding some prefetch statements, but for linear access like this that's usually not going to help much. The real issue (if I may be so bold) is all the TLB misses. Let's measure.

Here's the starting point on my test system, an Intel Sandy Bridge E5-1620 with 1600 MHz quad-channel RAM:

      $ perf stat bytesum 1gb_file
      Size: 1073741824
      The answer is: 4
      Performance counter stats for 'bytesum 1gb_file':

      262,315 page-faults         #    1.127 M/sec
      835,999,671 cycles          #    3.593 GHz
      475,721,488 stalled-cycles-frontend   #   56.90% frontend cycles idle
      328,373,783 stalled-cycles-backend    #   39.28% backend  cycles idle
      1,035,850,414 instructions            #    1.24  insns per cycle
      0.232998484 seconds time elapsed

Hmm, those 260,000 page-faults don't look good. And we've got 40% idle cycles on the backend. Let's try switching to 1 GB hugepages to see how much of a difference it makes:

      $ perf stat hugepage 1gb_file
      Size: 1073741824
      The answer is: 4
      Performance counter stats for 'hugepage 1gb_file':

      132 page-faults               #    0.001 M/sec
      387,061,957 cycles                    #    3.593 GHz
      185,238,423 stalled-cycles-frontend   #   47.86% frontend cycles idle
      87,548,536 stalled-cycles-backend     #   22.62% backend  cycles idle
      805,869,978 instructions              #    2.08  insns per cycle
      0.108025218 seconds time elapsed

It's entirely possible that I've done something stupid, but the checksum comes out right, but the 10 GB/s read speed is getting closer to what I'd expect for this machine. Using these 1 GB pages for the contents of a file is a bit tricky, since they need to be allocated off the hugetlbfs filesystem that does not allow writes and requires that the pages be allocated at boot time. My solution was a run one program that creates a shared map, copy the file in, pause that program, and then have the bytesum program read the copy that uses the 1 GB pages.

Now that we've got the page faults out of the way, the prefetch suggestion becomes more useful:

      $ perf stat hugepage_prefetch 1gb_file
      Size: 1073741824
      The answer is: 4

      Performance counter stats for 'hugepage_prefetch 1gb_file':
     132 page-faults            #    0.002 M/sec
     265,037,039 cycles         #    3.592 GHz
     116,666,382 stalled-cycles-frontend   #   44.02% frontend cycles idle
     34,206,914 stalled-cycles-backend     #   12.91% backend  cycles idle
     579,326,557 instructions              #    2.19  insns per cycle
     0.074032221 seconds time elapsed

That gets us up to 14.5 GB/s, which is more reasonable for a a single stream read on a single core. Based on prior knowledge of this machine, I'm issuing one prefetch 512B ahead per 128B double-cacheline. Why one per 128B? Because the hardware "buddy prefetcher" is grabbing two lines at a time. Why do prefetches help? Because the hardware "stream prefetcher" doesn't know that it's dealing with 1 GB pages, and otherwise won't prefetch across 4K boundaries.

What would it take to speed it up further? I'm not sure. Suggestions (and independent confirmations or refutations) welcome. The most I've been able to reach in other circumstances is about 18 GB/s by doing multiple streams with interleaved reads, which allows the processor to take better advantage of open RAM banks. The next limiting factor (I think) is the number of line fill buffers (10 per core) combined with the cache latency in accordance with Little's Law.

<comment><USER7> Good stuff! The low numbers (4 GB/s, one tenth the available memory bandwidth) that we're seeing sounds like a lot of time is wasted in page faults (and indeed, perf stat confirms it). However, the solution you propose sounds difficult, you need a special file system and need to know what kind of page sizes the CPU supports.

Can you think of ways to get reduce the number of page faults from inside the application itself? Or methods that would be portable to architectures with different page sizes?

I tried a simple call to madvise and posix_fadvise to inform the operating system ahead of time that I am going to need the memory but that did not have any effect on the number of page faults.

Any other tips for squeezing some more perf out? Did you happen to do any cache miss stats your benchmarks?

<comment><USER17> You get a similar effect to huge pages by passing MAP_POPULATE to mmap, which pre-faults all pages itself before returning.

<comment><USER27> What do you think MAP_POPULATE is actually doing here? Unless it's changing the page size, I don't see how it would be significantly reducing the number of TLB misses. Is it perhaps doing the preloading in a separate thread on a different core? And the timing happens to work out that so that the L3 cache is getting filled at the same rate it's being drained?

<comment><USER7> > What do you think MAP_POPULATE is actually doing here? Unless it's changing > the page size, I don't see how it would be significantly reducing the number > of TLB misses.

I think that MAP_POPULATE here will fill the page table with entries rather than leaving the page table empty and letting the CPU interrupt at (almost) every time a new page is accessed. That would be about 200k less interrupts for a 1G file.

MAP_POPULATE will probably also do the whole disk read in one go rather than in a lazy+speculative manner.

Page size is probably not affected and neither is number of TLB misses. I in my testing that the size of the file (and the mapping) will affect the page size, a 4G had significantly less page fault interrupts than a 500MB file.

And obviously, MAP_POPULATE is bad if physical memory is getting exhausted.

<comment><USER27> I came across this link, which helped me understand the process a bit better: [http://kolbusa.livejournal.com/108622.html](http://kolbusa.livejournal.com/108622.html). So yes, the main savings seems to be that the page table is created in a tight loop rather than ad hoc. Given the number of pages in the scane, it's still going to be a TLB miss for each page, but it will be just a lookup (no context switch).

 _in my testing that the size of the file (and the mapping) will affect the page size_

I'm doubtful of this, although it might depend on how you have "transparent huge pages" configured. But even then, I don't think Linux currently supports huge pages for file backed memory. I think something else might be happening that causes the difference you see. Maybe just the fact that the active TLB can no longer fit in L1?

 _And obviously, MAP_POPULATE is bad if physical memory is getting exhausted._

I'm confused by this, but this does appear to be the case. It seems strange to me that the MAP_POPULATE|MAP_NONBLOCK is no longer possible. I was slow to realize this may be closely related to Linus's recent post: [https://plus.google.com/+LinusTorvalds/posts/YDKRFDwHwr6](https://plus.google.com/+LinusTorvalds/posts/YDKRFDwHwr6)

</comment></comment></comment></comment></comment></comment><comment><USER28> The author's SSE code is a _terribly_ overcomplicated way of summing up every byte. The code is using PMADDW (a multiply and add?!), and is strangely trying to interleave hardcoded 0s and 1s into registers with PUNPCKHBW/PUNPCKLBW, huh?

All the author needs is PADDB (add packed bytes).

<comment><USER28> Here is how it should be done with PADDB: [http://pastebin.com/MY9tENpW](http://pastebin.com/MY9tENpW) This is 20% faster than the author's version on my computer: 0.210 sec vs. 0.260 sec to process 1GiB. The tight loop is simple:

      400710:	66 0f fc 04 07       	paddb  (%rdi,%rax,1),%xmm0
      400715:	48 83 c0 10          	add    $0x10,%rax
      400719:	48 39 c6             	cmp    %rax,%rsi
      40071c:	77 f2                	ja     400710 <sum_array+0x10>

Compare this to the author's complex version:

      400720:	66 0f 6f 14 07       	movdqa (%rdi,%rax,1),%xmm2
      400725:	48 83 c0 10          	add    $0x10,%rax
      400729:	48 39 c6             	cmp    %rax,%rsi
      40072c:	66 0f 6f c2          	movdqa %xmm2,%xmm0
      400730:	66 0f 68 d4          	punpckhbw %xmm4,%xmm2
      400734:	66 0f 60 c4          	punpcklbw %xmm4,%xmm0
      400738:	66 0f f5 d1          	pmaddwd %xmm1,%xmm2
      40073c:	66 0f f5 c1          	pmaddwd %xmm1,%xmm0
      400740:	66 0f fe c3          	paddd  %xmm3,%xmm0
      400744:	66 0f fe c2          	paddd  %xmm2,%xmm0
      400748:	66 0f 6f d8          	movdqa %xmm0,%xmm3
      40074c:	77 d2                	ja     400720 <sum_array+0x20>

</comment></comment><comment><USER29> Nice. I remember the first time I really internalized how fast computers were, even when people claimed they were slow. At the time I had a "slow" 133Mhz machine but we kept finding things it was doing that it didn't need too, and by the time we had worked through that there it was idling a lot while doing our task.

The interesting observation is that computers got so fast so quickly, that software is wasteful and inefficient. Why optimize when you can just throw CPU cycles or memory at the problem? What made that observation interesting for me was that it suggested the next 'era' of computers after Moore's law stopped was going to be about who could erase that sort of inefficiency the fastest.

I expect there won't be as much time in the second phase, and at the end you'll have approached some sort of limit of compute efficiency.

And hats off for perf, that is a really cool tool.

</comment><comment><USER30> It's pretty clear that we're wasting unbelievably huge amounts of computing power with the huge stacks of abstraction we're towering on.

So let's make this interesting, assuming a ground up rewrite of an entire highly optimized web application stack - from the metal on up, how many normal boxes full of server hardware could really just be handled by one? 2? a dozen?

I'd be willing to bet that a modern machine with well written, on the metal software could outperform a regular rack full of the same machines running all the nonsense we run on today.

Magnified over the entire industry, how much power and space are being wasted? What's the dollar amount on that?

What's the developer difference to accomplish this? 30% time?

What costs more? All the costs of potentially millions of wasted machines, power and cooling or millions of man hours writing better code?

<comment><USER31> I'll take that bet.

We gain a lot with "the huge stack of abstraction". The OS gives us a ton of "goodies" for free (memory abstraction, process/thread safety, networking, etc) and the languages/libraries give us more goodies (the ability to focus on higher-level tasks rather than "bit twiddling"). One could also point to the fact that your team is taking advantage of hundreds (thousands?) of domain experts in every aspect of the stack to get the "best" solution.

I would argue that it's not "30% time". It's the accumulated time of each level of abstraction you are using combined. It is very likely the case that one team couldn't rewrite the web application stack "from the metal up" and offer significant improvements.

<comment><USER30> Still it's pretty shocking that billions of people might have to wait even a noticeable unit of time that can often be measured in seconds for a web page to go from request to final render. We're doing something wrong.

Server and desktop computing power is impressively more powerful today than when this [1] was first created, which loads almost as fast as I can take my finger off of the mouse button that clicked the link to take me there

1 - [http://info.cern.ch/hypertext/WWW/TheProject.html](http://info.cern.ch/hypertext/WWW/TheProject.html)

yet I was able to actually count "one onethousand two onethousand three onethousand" before www.youtube.com finished rendering. I don't know, is 2.xx seconds times a billion people more efficient than a few hundred developers spending 2x or 3x longer to write efficient code?

<comment><USER31> I would say that it's a combination of both. I personally don't automatically assume the delay when clicking a link is due to the number of abstractions between my mouse and the server-side hardware that a website is running on.

In the YouTube example, you have very real speed-of-light constraints. I fired up the Chrome debugger and loaded the main site. I had over 100 requests in the first couple of seconds. Even with a very low-latency connection, assuming that your browser can "batch" the requests together, and instantaneous server response there still is an overhead of request/response of at least tens of milliseconds for each request (or group of requests).

To reduce that time, it requires reducing the number of requests, assuming that javascript/images are already loaded, parallelizing or delaying the loading of "ancillary data" etc. All of which have nothing to do with the speed of the server or the client.

</comment></comment></comment></comment><comment><USER32> Nice writeup! I like how even simplistic approaches to performance can easily show clear differences! However! I noticed you use many (many!) exclamation points! It gave me the impression that you used one too many caffeine patches! [1]

[1]: [https://www.youtube.com/watch?v=UR4DzHo5hz8](https://www.youtube.com/watch?v=UR4DzHo5hz8)

<comment><USER20> Shows how excited they were. I always like to see blog posts where the poster is excited about the post!

</comment></comment><comment><USER33> > So I think that means that it spends 32% of its time accessing RAM, and the > other 68% of its time doing calculations

Not sure if you can do such conclusion actually, because of pipelining etc. I'd assume that the CPU is doing memory transfers simultaneously while doing the calculations.

I also think that only the first movdqa instruction is accessing RAM, the others are shuffling data from one register to another inside the CPU. I'd venture a _guess_ that the last movdqa is shown taking so much time because of a pipeline stall. That would probably be the first place I'd look for further optimization.

On the other hand, I don't have a clue about assembly programming or low-level optimization, so take my comments with a chunk of salt.

<comment><USER10> It spends the other 68% of its time doing calculations _and waiting for the results of the memory accesses_.

I personally don't like using per-instruction timings like the one presented in the article to measure performance; on a pipelined, superscalar/out-of- order CPU, the fact that one instruction takes a long time to execute doesn't matter so much since others can execute "around it" if they don't depend on it.

On the other hand, macrobenchmarks like the timing of the execution of a whole program, _are_ very useful.

 _I timed it, and it took 0.5 seconds!!! [...] So our program now runs twice as fast_

0.5s down from 0.6s is not "twice as fast", it is a 16.67% improvement. I'm not sure where the 0.25s was pulled from.

<comment><USER33> > It spends the other 68% of its time doing calculations and waiting for the > results of the memory accesses.

It is bit odd though, the code is processing data at about 4GB/s, and modern system should have lot more RAM bandwidth (eg about 10GB/s for DDR3-1333). It feels like there should be still significant room for optimization.

> 0.5s down from 0.6s is not "twice as fast", it is a 16.67% improvement. I'm > not sure where the 0.25s was pulled from.

I think the 0.5 was typo (missing '2') and should be instead 0.25

<comment><USER8> Yes, there is a room for optimization. It seems to me bytesum_intrinsics.c doesn't saturate RAM bandwidth because loops are not unrolled. You should unroll the loop in addition to SIMD so that SIMD loads complete while SIMD adds are done, hiding memory latency. Otherwise you wait on loads.

<comment><USER10> _so that SIMD loads complete while SIMD adds are done_

That's almost certainly already being done by the hardware. Loop unrolling has been counterproductive ever since ~Sandy Bridge or so, and probably hasn't been that great of an idea since the post-P4 days:

[http://www.agner.org/optimize/blog/read.php?i=142#142](http://www.agner.org/optimize/blog/read.php?i=142#142)

 _It is so important to economize the use of the micro-op cache that I would give the advice never to unroll loops._

<comment><USER8> This is a great advice, but I think it doesn't apply here. If code normally fits in uop cache but unrolled code doesn't, you are punished. But here both normal code and unrolled code fit uop cache.

Loop unrolling may be counterproductive, but loop unrolling for vectorization almost certainly isn't, even in the current CPUs. It really can't be done by the hardware, and all compilers unroll loops for vectorization, even if you disable loop unrolling in general.

<comment><USER27> You are correct that both fit in uop cache, but I think 'userbinator' is correct here that loop unrolling is of very limited benefit here (and almost everywhere else). Because of speculative execution, processors are basically blind to loops. They will keep executing ahead along the most likely path even if this means they are simultaneously executing different iterations of a loop. The loads will pre-execute just fine across the loop boundary. While there are cases where reducing the amount of loop logic will speed things up, it really can be done in hardware!

</comment></comment></comment></comment></comment></comment></comment><comment><USER8> I wonder why GCC does not autovectorize the loop in bytesum.c even with -Ofast. With autovectorizer, GCC should make the plain loop as fast as SIMD intrinsics. Autovectorizer can't handle complex cases, but this is as simple as it can get.

Anyone has ideas?

<comment><USER34> I don't think compilers are able to know when to use SIMD

Isn't vectorization different than SIMD ?

<comment><USER16> No, vectorization is converting scalar operations (i.e. one piece of data at a time, e.g. summing one byte at a time) to vector ones (operating on multiple pieces of data at once, e.g. summing 16 bytes in parallel), and these operations are exactly what SIMD is.

</comment></comment></comment><comment> enjoy-your-stay The first time I realised how fast computers _could_ be was when I first booted up BeOS on my old AMD single core, probably less than 1Ghz machine.

The thing booted in less than 10 seconds and performed everything so quickly and smoothly - compiling code, loading files, playing media and browsing the web (dial up modem then).

It performed so unbelievably well compared to Windows and even Linux of the day that it made me wonder what the other OSes were doing differently.

Now my 4 core SSD MacBook pro has the same feeling of raw performance, but it took a lot of hardware to get there.

</comment><comment><USER10> One of the things I've always wanted is autovectorisation by the CPU - <USER2> if there was a REP ADDSB/W/D/Q instruction (and naturally, repeated variants of the other ALU operations.) It could make use of the full memory bandwidth of any processor by reading and summing entire cache lines the fastest way the current microarchitecture can, and it'd also be future-proof in that future models may make this faster if they e.g. introduce a wider memory bus. Before the various versions of SSE there was MMX, and now AVX, so the fastest way to do something like sum bytes in memory changes with each processor model; but with autovectorisation in hardware, programs wouldn't need to be recompiled to take advantage of things like wider buses.

Of course, the reason why "string ALU instructions" haven't been present may just be because most programs wouldn't need them and only some would receive a huge performance boost, but then again, the same could be said for the AES extensions and various other special-purpose instructions like CRC32...

<comment><USER35> This is why I'm in favor of client-side compilation.

Devs compile to an intermediate language or bytecode of some sort, which then gets compiled on installation / first use / update of the client runtime client-side. Kind of like Java, but instead of being JITted (which causes inconsistent performance) it's compiled and cached.

That way things can be optimized for your specific architecture / computer.

Of course, you can actually do this at the kernel level.

</comment></comment><comment><USER36> Anyone notice how the author is all excited? Got me in a good mood, reading this.

</comment><comment><USER37> Great post. If you want to dig in even deeper you can learn certain nuances of underlying assembly language like loop unrolling, reducing the number of memory accesses, number of branch instructions per iteration of any loops by rewriting the loop, rearranging instructions or register usage to reduce the dependencies between instructions.

I took a CPSC course last year and for one of the labs we improved the performance of fread and fwrite C library calls by playing with the underlying assembly. We maintained a leader board with the fastest times achieved and it was a lot of fun to gain insight into the low level mechanics of system calls.

I digged up the link to the lab description - [http://www.ugrad.cs.ubc.ca/~cs261/2013w2/labs/lab4.html](http://www.ugrad.cs.ubc.ca/~cs261/2013w2/labs/lab4.html)

</comment><comment><USER38> The rest of her blog is great as well, I really like her stuff about os-dev with rust.

</comment><comment><USER39> Naïve Python3 is not as fast as Numpy, but pretty elegant:

      def main(filename):
          d = open(filename, 'rb').read()
          result = sum(d) % 256
          print("The answer is: ", result)

<comment><USER40> Note that sum(d) will generate a huge number, possibly using lots of memory and processing power. A better option would be:

        def main(filename):
          d = open(filename, 'rb').read()
          result = reduce(lambda i, j: (i + j) % 256, d)
          print("The answer is: ", result)

Note how this is similar to the squaring algorithm used in cryptography: [http://en.wikipedia.org/wiki/Exponentiation_by_squaring](http://en.wikipedia.org/wiki/Exponentiation_by_squaring)

<comment><USER39> That approach would be very well adapted to a low-level language such as C with the risk of overflow.

Python handles long integers transparently, and the overhead of managing the lambda function and additional variables in Python is probably much more time consuming than handling a long integer.

</comment></comment></comment><comment><USER41>
      I timed it, and it took 0.5 seconds!!!
      So our program now runs twice as fast,

minor typo above: time is later stated as 0.25. super neat!

<comment><USER42> I wrote a comment pointing that out on the author's blog, but it appears to have since been deleted :/

</comment></comment><comment><USER43> But not fast enough</comment>


Recruiting in a buyer's market - <AUTHOR> https://www.linkedin.com/pulse/recruiting-buyers-market-paul-coia

<comment><USER2> A couple of good takeaways-- Companies will need to pay upfront retainers to get the right talent. Agency recruiters, evolve or die.</comment>


Was Anne Frank's family betrayed? After 72 years, historians have a new theory - <AUTHOR> https://www.washingtonpost.com/news/worldviews/wp/2016/12/17/was-anne-franks-family-betrayed-after-72-years-historians-have-a-new-theory/ <comment><USER2> I recommend visiting the Anne Frank house if you have a couple hours free in Amsterdam. It is powerful and moving.

And don't miss the linked article [0] about Bana, the 7 year old in Aleppo that I and everyone in the West have failed.

[0] [https://www.washingtonpost.com/lifestyle/style/how-a-7-year-...](https://www.washingtonpost.com/lifestyle/style/how-a-7-year- old-aleppo-girl-on-twitter-became-our-eras-anne- frank/2016/12/06/b474af5c-bb09-11e6-91ee-1adddfe36cbe_story.html)

<comment><USER3> I suspect this article is going to get some heated discussion pretty quickly.

I don't believe you have failed anyone and I hope you'll allow me to explain why I think so.

In the West (and developed countries), we expect our local authorities to deal with problems we see on a day to day basis. And they do. When you see a car accident, you call 911 and an ambulance and fire crew arrive, cut trapped people out and take them to hospital where doctors and nurses work to treat their injuries. Meantime, police turn up, close the road, help clear things up, set diversions and get traffic flowing, then clear everything up and everything goes back to normal.

Naturally, used to all this potency of our 'leaders', we see another horrible situation (e.g. Syria) and, based on our experience, we naturally expect our leaders to step in and fix that horrible situation too.

But they cannot.

To do so, _you_ need to _want_ your country to act like a colonial power and send in troops - some of whom will be killed - in order to suppress and defeat the evils we are so upset about.

We know from history that a colonial power, suppressing a local authority, must be prepared to be brutal (even more so than those being suppressed) in order to succeed.

But no-one wants to be a colonial power (ok, it's frowned upon in reasonably liberal democracies at least).

And any recent attempts (Vietnam on) have ended in miserable failure and basically made things worse.

Even if you are advocating for some World Police to move in and take over, there isn't even agreement on who that would be. Russians see that as their role, Americans see it as their role.

Neither country would accept the other doing it exclusively nor would they really be able to work together to do it as they both have different standards of what is acceptable and what is not.

So, unless there is an answer to all that, neither you nor anyone else outside the theater has a personal responsibility.

That does not stop you feeling legitimately upset or anguished about the situation. That's something completely different. But don't confuse the two issues.

<comment><USER4> Interest in regime change caused the crisis in Syria. Let's not kid ourselves. Our leaders are responsible for that mess. And they have no clue as to how to fix it. The whole thing was social engineering plot to get rid of Assad in the mist of Arab Spring. And that caused a civil war. Oops. Arabs have been at the mercy of American ambitions which are jaded by Saudi ambitions to mold the whole region into an area sympathetic to their interests. And they have been playing one monster against another at the cost of Arabs for decades. Meanwhile taking no responsibility for any of it, and blaming it on the monsters that they constantly help mold and manipulate. Yes the monsters were there to begin with, but their meddling creates chaos in the power structure that causes constant catastrophe.

<comment><USER5> So the solution is to meddle more and this time 'the west' will shit unicorns and rainbows right?

That's why many people don't want their government to meddle in it and why it's not 'everyone in the west's' failing. Of course, these people didn't want to meddle in the first place.

<comment><USER4> I agree with that. But if you don't want to meddle then you have to quit supplying the region and pull out... Which is not going to happen. Obama sold the Saudis 150 billion dollars in ammo. You think that's going to stop. UK same thing. Germany same thing. The meddling starts with business... but it does not end there.

As Tupac said, " Give 'em guns, step back, and watch 'em kill each other."...</comment></comment></comment></comment></comment>


Where Anti-Tax Fervor Means 'All Services Will Cease' - <AUTHOR> https://www.nytimes.com/2017/05/13/us/anti-tax-fervor-roseburg-oregon-.html?hpw&rref=us&action=click&pgtype=Homepage&module=well-region&region=bottom-well&WT.nav=bottom-well <comment><USER2> This piece does a fairly good job of presenting the conservative point of view: that there are mountains of waste in government to cut rather than hike taxes. I agree with that perspective.

Unfortunately, as we've seen from Republican-led governments operating under this Grover Norquist-esque model for thirty years, the beast never starves. In Washington DC they print money to offset deficits. Instead of cutting waste, the libraries and the parks are closed.

There's still a great desire out there for responsible government that can operate efficiently. That can keep the libraries open by trimming bureaucratic waste rather than asking for more money. Probably will always be a pipe dream.

<comment><USER3> My local government is really transparent about the budget, where it's going. They've been running really lean since the great recession. It's really interesting to see how they spend money. There are couple programs I question, but for the most part they do an excellent job. I will say sometimes a few years after these programs are implemented I'm generally a fan.

I understand the drive to make government more efficient, run better, but I'm not sure if that's the goal of the current conservative movement. At least here in Michigan the state government under republican control has caused all sorts of issues, like the Flint water crisis.

<comment><USER4> A couple of my friends are in low-level positions with the state government. At least in their cases, I can say that their offices run so lean that cost- cutting attempts from higher up just lead to worse service and conflicting (or outright illegal) directives, which encourage rule-breaking of a sort that is sure to eventually bite them in the ass in expensive ways.

</comment></comment></comment><comment><USER5> From someone of a Norwegian/Australian background, what the whole article describes is simply alien. People just aren't that _selfish_ on a grand scale in either of my home countries.

Clearly, none of the non-voters ever read Matilda. Or understand that ultimately, the lack of public services will put everyone back.

<comment><USER6> As a Norweigan, you may not be in possession of certain facts about the US politics.

1\. Almost all media in the US is severely biased.

2\. This to me at least looks like something called the "national parks strategy." This is when the government funds its unpopular pet projects (frequently theft), and underfunds popular programs such as national parks, roads and the like then threatens the public with their closure if they do not pass tax increases. Frequently, if the tax is passed, they do a show project and misallocate the rest of the money. Over the time citizens have become wise and vote--entirely rationally-- for the safest option which is, no new taxes.

California is in the midst of such a battle now: [http://www.washingtontimes.com/news/2017/may/11/californians...](http://www.washingtontimes.com/news/2017/may/11/californians- rebel-against-gas-car-tax-hike/)

<comment><USER7> The media isn't biased as much as you think. It's anti-confrontational, which means stories about things people are upset about often get minified. However, the Washington Times, which you linked to, is fantastically biased. It's owned by the Unification Church, and has been repeatedly criticized for its pro-Moon stance. If you want to know what's really happening, don't read the washington times.

<comment><USER8> US media is biased. Try this experiment: find a conservative friend and a liberal friend. Ask each of these friends which of the two papers in the parent and OP is more biased and which is more fact-based.

Your conservative friend will tell you the Washington Times is more fact-based and the New York Times is heavily biased. Your liberal friend will tell you the New York Times is more fact-based and the Washington Times is heavily biased.

Your first conclusion might be that one of your friends (whichever one whose beliefs oppose yours more) is insane or uneducated on what you know is true.

The more likely conclusion, however, is that each of these papers weaves heavy amounts of opinion, spin, and perspective on the "facts" it conveys, and that opinion and spin is invisible to those who share the same biases, while being conspicuous and grating to those who do not.

</comment></comment></comment></comment><comment><USER9> I think taxes are good. I don't mind paying taxes at all.

I want to support community services and public works and social equality.

The only context in which I really really hate paying tax is where I feel that the politicians are looting the public money to enrich themselves and give themselves generous employment benefits well beyond that of ordinary citizens.

<comment><USER10> It's more complex than politicians looting for personal enrichment, and it feels like those corruption cases are handled with an occasional FBI arrest here and there.

Ever notice how some of the political candidates are supported by some public employee unions, e.g. a candidate supported (and frequently financed) by police, teachers, prison guards, etc.?

Well, that same politician, once elected, is frequently in charge of negotiating the public sector compensation and pension benefits. In what might come as a total surprise, they turn out to have very weak negotiating skills when it comes to dealing with unions that invested in their previous rounds.

You don't have to look very far - as far as few years ago the city of San Jose had to suspend hiring policemen, and lay off some junior teachers due to funding issues. Meanwhile on the other end of the paycheck spectrum a bunch of public employees were throwing early retirement parties, having locked in a six-figure pension for the rest of their lives [http://www.mercurynews.com/2012/08/30/bay-areas-200k-club- an...](http://www.mercurynews.com/2012/08/30/bay-areas-200k-club-analysis- finds-fat-pensions-belong-to-nonunion-bosses/)

<comment><USER11> A good example of this is all the union busting the GOP were championing in the 2010s or so. The police and fire unions supported the GOP and the GOP went on to reduce some of the power of the worker's unions. Scott Walker is one of these politicians. The police and fire unions were left unharmed and are still strong.

There could be an argument that the strength of the police unions are partially to blame with the issues we are having with police shootings and lack of prosecution, among other things.

</comment></comment></comment><comment><USER12> "Only a crisis - actual or perceived - produces real change." \- Milton Friedman

Age 45 and up comprises the smallest number of HN readers, the largest number of Americans, the largest quantity of American voters, and the greatest concentration of wealth in America. This, majority demographic will support real change when there is no other option, but not before then. Most refuse to admit their generations enacted public policies that have left most cites States and the Federal Government irreversibly in debt.

Milton Friedman also said, "When that crisis occurs, the actions that are taken depend on the ideas that are lying around." Its critical that today's emerging leaders are well educated on what makes for sustainable economic and social policy, and what is required to dig ourselves out from the hole dug for us.

<comment><USER13> Much of the problem lies with future unfunded obligations in Social Security. When Social Security was enacted, the average life expectancy was 61 and the full retirement age was 65 - the average person died before getting a dime. This is no longer the case, and it's why the program is going bankrupt. I, at 35 years of age, am not planning to ever receive social security & am saving at a rate that reflects that (slightly over Dave Ramsey's recommended 15%). I will vote ASAP to raise the full retirement age to 84, which is 4 years after the national average life expectancy of 79. Doing this will fill in a significant portion of the hole that prior generations have dug.

I would also support raising the retirement age for women to a higher value than that for men, due to the difference in life expectancy. Equal opportunity to collect, and all (ducks head to dodge flying objects). OK, maybe I'm half kidding about that, but dead serious about everything else.

<comment><USER12> Underfunded State pensions are an even bigger problem. Insurmountable actually.

</comment></comment></comment><comment><USER3> In rural areas this seems like it will kill jobs and make the area less desirable.

There always is a balance to strike, not providing too many services at too high a cost, but killing off a library? Not being able to have police?

How is someone supposed to apply for a job if they don't have internet? How are they supposed to pull themselves up by their bootstraps? The library provides ways for people to get ahead.

<comment><USER14> Realistically every person in America can get enough money for a phone with internet access. An older used Android phone can be had for around $50. Internet is free in enough places that a phone with charger is sufficient.

A common and incorrect view of the homeless persists in America, to their peril. Destitute starving people exist in some countries but not those as rich as the US.

In the US and other wealthy countries basically 100% of chronic homeless are in that position due to drugs or mental illness. A normal person thrown on the street with nothing would be able to scrape together some semblance of a normal life within a few months.

This is hurting the homeless in the US greatly. The common view of homelessness as someone just "down on their luck" leads to bad attempts at solutions. Mentally stable adults without drug problems do not stay homeless in the US and rarely become homeless.

To help the homeless we need vastly increased spending on mental health and addiction treatment for the poor. We also need socialized housing for those too mentally I'll to ever hold a job. A lot of homeless people will be homeless unless someone pays for a place for them to live indefinitely.

</comment></comment><comment><USER15> Local, State, and Federal government spending as a percentage of the GDP continue to creep upward.

[http://www.usgovernmentspending.com/spending_chart_1900_2020...](http://www.usgovernmentspending.com/spending_chart_1900_2020USp_XXs2li111tcn_F0xF0sF0lF0f_Federal_State_and_Local_Spending_in_20th_Century)

It's surprising that the closing of some library branches is somehow the fault of overly paranoid tax-haters rather than out-of-control spending patterns.

</comment><comment><USER16> "More money in voters' wallets from tax cuts in Washington could reduce the sting in asking people to pay more at home, or it could just reinforce the idea that all taxes are meant to go down."

The latest tax plan that was floated means very few people in states like Oregon (with high state taxes) are going to see any reduction, because they're going to make those state taxes non-deductible. Not sure how that plays into this argument.

<comment><USER17> State taxes already aren't tax deductible for the middle class. The standard deduction for a married couple is $12000. If you have a mortgage on average price house* ($185,000), you're not clearing enough in mortgage interest and state taxes to make itemizing worthwhile.

I know there are other deductions, but I still doubt that the average middle income household ($60,000/year) is clearing over $12,000 in deductions.

[http://www.deptofnumbers.com/income/us/](http://www.deptofnumbers.com/income/us/)

[http://m.huffpost.com/us/entry/4957604](http://m.huffpost.com/us/entry/4957604)

</comment></comment><comment><USER18> I live a block away from a public library. It's so close that I can see it right outside my window!

And you know what? I have not been to that library ever, and I've lived in this neighborhood for years.

Even if you happen to use your library every day now, you probably won't be doing that in twenty years, regardless of whether or not they continue to offer service in your town.

Taking a wide view, what else should we expect, now that we have computers in our pockets connected to a far larger and more comprehensive source of knowledge?

There are a lot of details and small objections to my point here, to be sure, but the technology that's driving this trend is NOT going away.

<comment><USER18> I see I have three comments here, and I'll just state my main objection to all three of you (felipemnoa, gene-h, anigbrowl):

Ok, so when are the libraries/community centers going to turn those awful fluorescent lights off, bring in some comfortable couches and start serving alcohol and coffee?

Because if they don't start doing that, there's just no draw for me...

<comment><USER19> Might as well just go and sit at a bar with a computer. The library I go to you can at least bring your own coffee or any other liquids, except probably alcohol :)

<comment><USER18> I actually do this :joy:</comment></comment></comment></comment>


Ask HN: How to successfully grow a startup? - <AUTHOR>

I am one of the co-founders of fansunite.com a social, sports oriented, handicapping platform. 2013 was a very successful year for us. We found an angel investor who believed in what we were trying to accomplish, built our basic platform, hired a designer and two coders and moved into an office space. Two years ago I thought accomplishing all that would be the hard part and once we were up and running we had made it. Now here we are with our dream becoming a reality and the hard part is only beginning…. Growing an actively engaged community.
Ill give you a brief rundown of what we are currently doing and then ill pose my question.
-We set a goal of 5% growth per week (we are hitting and exceeding this goal every week since our launch 2 months ago)
-In order to hit that 5% target, each of the co-founders is actively targeting individuals on forums, twitter, facebook etc. and then re-engaging them on our site. Its working but is extremely labor intensive and as our user base grows, hitting that target every week is going to get harder and harder.
-We are also running contests centered around sporting events, which work to bring in large amounts of new users in batches.
-Twitter ads and Facebook ads were a waste of money. Lesson learned.
-Google ad words won't let us advertise.  Even though we are not a gambling site we use gambling terminology, which they don't like.
I'm curious how others with start-ups requiring user based content and social interaction, that are further along in the process than us, have had success growing their community? What worked and what was a waste of time? What are we missing?
I have no delusions about "going viral".  I believe the only way we will have success is with hard work and putting in a lot of man-hours.  I know there are success and failure stories in this community.  I'm hoping that people are willing to share, as there are learning experiences with both.
Thanks in advance. <comment><USER2> I would have to agree with xux's points. You really do want to make sign-up as simple as possible. Possibly even consider authentication with Facebook, Google, Twitter? (When trying new layouts/features you should keep A/B testing in mind)

Also, admittedly I haven't signed up so I don't know exactly how it works, but to build on what namenotrequired said, you really do what existing members to be the ones bringing in people. Perhaps you could make it a bit more 'personal', by allowing users to inside facebook friends, and possibly building private league boards where a group of friends can complete against themselves rather than with strangers. I think it's these sort of strategies that will help encourage users to invite their friends. Although it is important to make inviting new users as easy as possible, please don't over do it. There are many apps that force you to connect via facebook, or constantly badger their users to invite people. These tactics may be effective but personally I'm against these very aggressive acquisition tactics at the expense of your existing members' user experience.

</comment><comment><USER3> For now you've got a method of getting people there, even though it doesn't scale (I'm guessing you've read PG's advice on this[1]). I'd say that what matters right now is that those you're getting on your site, are returning and active.

Is that 5% growth in signups, or in something else? Are those members who you've successfully brought in returning every day? Do you have any indication of whether your members find value in your platform?

You say you have no delusions about "going viral" \- and indeed you won't go viral in the sense that a meme from 9gag goes viral, but communities do often depend on their members to refer others there. For that to happen, your product must provide good value to those members.

Talk to your members, if you aren't already, about how valuable your platform is for them. And while you're talking to them, maybe find out where else they hang out too? You'll probably find new places to recruit members from, and perhaps think of new ways to grow.

Good luck!

[1] [http://paulgraham.com/ds.html](http://paulgraham.com/ds.html)

<comment><AUTHOR> We have read Paul Grahams advice on doing things that don't scale. We built our current growth tactics around that article. The 5% is a measurement of new signups. I believe you are correct in that eventually our growth will come from current member referrals and when that begins to occur we can stop recruiting manually. We are actively engaging with our user base on our platform and on twitter. I believe, in our niche, they do find us of value. The larger the community the greater value we will have. I suppose giving members an incentive to refer friends is something we haven't tried that could work.

thanks for your feedback.

</comment></comment><comment><USER4> I've a suggestion to FansUnite. Instead of asking people to enter a username _and_ a email, why not just use email as the login name? Much less annoying.

Also, ask for Twitter handle _after_ the user finishes registration. You want your signup to be non-frictious as possible.

<comment><AUTHOR> We are working on one click social media sign up right now. So all those issues will be non issues soon enough. The problem with using their email as their users name is most people don't want their email address displayed for everyone to see. Or do you mean have them fill out those particulars after they have signed up? Either way they will have to fill that information out at some point.

</comment></comment><comment><USER5> 1\. Instead of signups, you should measure active users (MAU). Or you'll be fooling yourselves.

2\. Is there some way for existing active users to bring in more people? Work on that.

</comment><comment><USER6> What is your email? Would like to contact you to share few things. My startup has similar approach to you, but in different industry/field. Thanks.</comment>