Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Most low latency/high frequency programming jobs (based on job specs) appear to be implemented on unix platforms. In a lot of the specs they make particular request for people with "low latency linux" type of experience.

Assuming this does not mean a real-time linux OS, could people give me help with what this could be referring to? I know you can set CPU affinity to threads, but I am assuming they are asking for much more to it than that.

Kernel tuning? (although I heard manufacturers like solarflare produce kernel bypass network cards anyway)?

What about DMA or possibly shared memory between processes? If people could give me brief ideas I can go and do the research on google.

(This question will probably require somebody familiar with High Frequency Trading)

share|improve this question
add comment

2 Answers 2

up vote 12 down vote accepted

I've done a fair amount of work supporting HFT groups in IB and Hedge Fund settings. I'm going to answer from the sysadmin view, but some of this is applicable to programming in such environments as well.

There are a couple of things an employer is usually looking for when they refer to "Low Latency" support. Some of these are "raw speed" questions (do you know what type of 10g card to buy, and what slot to put it in?), but more of them are about the ways in which a High Frequency Trading environment differs from a traditional Unix environment. Some examples:

  • Unix is traditionally tuned to support running a large number of processes without starving any of them for resources, but in an HFT environment, you are likely to want to run one application with an absolute minimum of overhead for context switching, and so on. As a classic small example, turning on hyperthreading on an Intel CPU allows more processes to run at once -- but has a significant performance impact on the speed at which each individual process is executed. As a programmer, you're likewise going to have to look at the cost of abstractions like threading and RPC, and figure out where a more monolithic solution -- while less clean -- will avoid overhead.

  • TCP/IP is typically tuned to prevent connection drops and make efficient use of the bandwidth available. If your goal is to get the lowest latency possible out of a very fast link -- instead of to get the highest bandwidth possible out of a more constrained link -- you're going to want to adjust the tuning of the network stack. From a programming side, you'll likewise going to want to look at the available socket options, and figure out which ones have defaults more tuned for bandwidth and reliability than for reducing latency.

  • As with networking, so with storage -- you're going to want to know how to tell a storage performance problem from an application problem, and learn what patterns of I/O usage are least likely to interfere with your program's performance (as an example, learn where the complexity of using asynchronous IO can pay off for you, and what the downsides are).

  • Finally, and more painfully: we Unix admins want as much information on the state of the environments we monitor as possible, so we like to run tools like SNMP agents, active monitoring tools like Nagios, and data gathering tools like sar(1). In an environment where context switches need to be absolutely minimized and use of disk and network IO tightly controlled, though, we have to find the right tradeoff between the expense of monitoring and the bare-metal performance of the boxes monitored. Similarly, what techniques are you using that make coding easier but are costing you performance?

Finally, there are other things that just come with time; tricks and details that you learn with experience. But these are more specialized (when do I use epoll? why do two models of HP server with theoretically identical PCIe controllers perform so differently?), more tied to whatever your specific shop is using, and more likely to change from one year to another.

share|improve this answer
    
Thank you, although I was interested in a programming answer this was very useful and informative. –  user997112 Jan 15 '13 at 22:14
2  
@user997112 This is a programming answer. If it doesn't seem as such, keep reading it until it does :) –  Tim Post Jan 16 '13 at 14:45
add comment

In addition to the excellent hardware/setup tuning answer from @jimwise, "low latency linux" is implying:

  • C++ for reasons of determinism (no surprise delay while GC kicks in), access to low-level facilities (I/O, signals), language power (full use of TMP and STL, type safety).
  • prefer speed-over-memory: >512 Gb of RAM is common; databases are in-memory, cached up-front, or exotic NoSQL products.
  • algorithm choice: as-fast-as-possible versus sane/understandable/extensible, e.g. lock-free, multiple bit arrays instead of array-of-objects-with-bool-properties.
  • full use of OS facilities such as Shared Memory between processes on different cores.
  • secure. HFT software is usually co-located in an Stock Exchange so malware possibilities are unacceptable.

Many of these techniques have overlap with games development which is one reason why the financial software industry absorbs any recently-redundant games programmers (at least until they pay their rent arrears).

The underlying need is to be able to listen to a very high bandwidth stream of market data such as security (stocks, commodities, fx) prices and then make a very fast buy/sell/do-nothing decision based on the security, the price and current holdings.

Of course, this can all go spectacularly wrong, too.


So i'll elaborate on the bit arrays point. Let's say we have a High Frequency Trading system that operates on a long list of Orders (Buy 5k IBM, Sell 10k DELL, etc). Let's say we need to quickly determine if all of the orders are filled, so that we can move onto the next task. In traditional OO programming, this is going to look like:

class Order {
  bool _isFilled;
  ...
public:
  inline bool isFilled() const { return _isFilled; }
};

std::vector<Order> orders;
bool needToFillMore = std::any_of(orders.begin(), orders.end(), 
  [](const Order & o) { return !o.isFilled(); } );

the algorithmic complexity of this code going to be O(N) as it is a linear scan. Let's take a look at the performance profile in terms of memory accesses: each iteration of the loop inside std::any_of() is going to call o.isFilled(), which is inlined, so becomes a memory access of _isFilled, 1 byte (or 4 dependending on your architecture, compiler and compiler settings) in an object of let's say 128 bytes total. So we're accessing 1 byte in every 128 bytes. When we read the 1 byte, presuming worst-case, we'll get a CPU data cache miss. This'll cause a read request to RAM which reads an entire line from RAM (see here for more info) just to read out 8 bits. So the memory access profile is proportional to N.

Compare this with:

const size_t ELEMS = MAX_ORDERS / sizeof (int);
unsigned int ordersFilled[ELEMS];

bool needToFillMore = std::any_of(ordersFilled, &ordersFilled[ELEMS+1],
   [](int packedFilledOrders) { return !(packedOrders == 0xFFFFFFFF); }

the memory access profile of this, assuming worst-case again, is ELEMS divided by the width of a RAM line (varies - could be dual-channel or triple-channel, etc).

So, in effect, we're optimising algorithms for memory access patterns. No amount of RAM will help - it's the CPU data cache size that causes this need.

Does this help?

share|improve this answer
    
"multiple bit arrays instead of array-of-objects-with-bool-properties" what do you mean by this? –  user997112 Feb 19 '13 at 22:46
1  
I've elaborated with examples and links. –  JBRWilkinson Feb 23 '13 at 12:07
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.