Latensi Rendah Unix / Linux

11

Sebagian besar pekerjaan pemrograman latensi rendah / frekuensi tinggi (berdasarkan spesifikasi pekerjaan) tampaknya diimplementasikan pada platform unix. Dalam banyak spesifikasi mereka membuat permintaan khusus untuk orang-orang dengan jenis pengalaman "linux latensi rendah".

Dengan asumsi ini tidak berarti OS linux waktu nyata, bisakah orang memberi saya bantuan dengan apa yang dimaksud? Saya tahu Anda dapat mengatur afinitas CPU ke utas, tetapi saya berasumsi mereka meminta lebih dari itu.

Pencarian kernel? (walaupun saya mendengar produsen seperti solarflare menghasilkan kartu jaringan bypass kernel)?

Bagaimana dengan DMA atau mungkin berbagi memori antar proses? Jika orang bisa memberi saya ide-ide singkat saya bisa pergi dan melakukan penelitian di google.

(Pertanyaan ini mungkin akan membutuhkan seseorang yang akrab dengan Perdagangan Frekuensi Tinggi)

pengguna997112
sumber
2
Tuning kernel adalah cara untuk membuat OS non-real-time senyata mungkin. Pinning thread juga wajib. Anda dapat membaca lebih lanjut tentang itu di artikel ini: coralblocks.com/index.php/2014/04/...
rdalmeida
Juga terkait: stackoverflow.com/q/15702601/632951
Pacerier

Jawaban:

26

Saya telah melakukan cukup banyak pekerjaan yang mendukung kelompok HFT dalam pengaturan IB dan Hedge Fund. Saya akan menjawab dari tampilan sysadmin, tetapi beberapa di antaranya berlaku untuk pemrograman di lingkungan seperti itu juga.

Ada beberapa hal yang biasanya dicari majikan ketika mereka merujuk pada dukungan "Latensi Rendah". Beberapa di antaranya adalah pertanyaan "kecepatan cepat" (apakah Anda tahu jenis kartu 10g yang akan dibeli, dan slot apa yang digunakan untuk memasukkannya?), Tetapi lebih banyak lagi tentang cara di mana lingkungan Perdagangan Frekuensi Tinggi berbeda dari tradisional Lingkungan unix. Beberapa contoh:

  • Unix secara tradisional disetel untuk mendukung menjalankan sejumlah besar proses tanpa membuat mereka kelaparan untuk sumber daya, tetapi dalam lingkungan HFT, Anda mungkin ingin menjalankan satu aplikasi dengan minimum overhead mutlak untuk pengalihan konteks, dan sebagainya. Sebagai contoh kecil klasik, menyalakan hiphreading pada CPU Intel memungkinkan lebih banyak proses berjalan sekaligus - tetapi memiliki dampak kinerja yang signifikan pada kecepatan di mana setiap proses individu dieksekusi. Sebagai seorang programmer, Anda juga harus melihat biaya abstraksi seperti threading dan RPC, dan mencari tahu di mana solusi yang lebih monolitik - meskipun kurang bersih - akan menghindari overhead.

  • TCP / IP biasanya disetel untuk mencegah penurunan koneksi dan membuat efisien penggunaan bandwidth yang tersedia. Jika tujuan Anda adalah untuk mendapatkan latensi serendah mungkin dari tautan yang sangat cepat - alih-alih mendapatkan bandwidth tertinggi dari tautan yang lebih terbatas - Anda ingin menyesuaikan penyetelan tumpukan jaringan. Dari sisi pemrograman, Anda juga akan ingin melihat opsi soket yang tersedia, dan mencari tahu mana yang memiliki standar lebih disetel untuk bandwidth dan keandalan daripada untuk mengurangi latensi.

  • Seperti halnya jaringan, demikian juga dengan penyimpanan - Anda akan ingin tahu cara memberi tahu masalah kinerja penyimpanan dari masalah aplikasi, dan mempelajari pola penggunaan I / O apa yang paling tidak mungkin mengganggu kinerja program Anda (sebagai contoh, pelajari di mana kompleksitas penggunaan IO asinkron dapat membayar untuk Anda, dan apa kerugiannya).

  • Akhirnya, dan yang lebih menyakitkan: kami para admin Unix menginginkan sebanyak mungkin informasi tentang keadaan lingkungan yang kami pantau, jadi kami ingin menjalankan alat seperti agen SNMP, alat pemantauan aktif seperti Nagios, dan alat pengumpulan data seperti sar (1). Dalam lingkungan di mana konteks switch harus benar-benar diminimalkan dan penggunaan disk dan jaringan IO dikontrol dengan ketat, kita harus menemukan tradeoff yang tepat antara biaya pemantauan dan kinerja bare-metal dari kotak yang dipantau. Demikian pula, teknik apa yang Anda gunakan yang membuat pengkodean lebih mudah tetapi biaya kinerja Anda?

Akhirnya, ada hal-hal lain yang datang seiring waktu; trik dan detail yang Anda pelajari dengan pengalaman. Tetapi ini lebih khusus (kapan saya menggunakan epoll? Mengapa dua model server HP dengan pengontrol PCIe yang identik secara teoretis bekerja sangat berbeda?), Lebih terikat pada apa pun yang digunakan toko khusus Anda, dan lebih mungkin untuk berubah dari satu tahun ke tahun lainnya .

jimwise
sumber
1
Terima kasih, walaupun saya tertarik pada jawaban pemrograman, ini sangat berguna dan informatif.
user997112
5
@ user997112 Ini adalah jawaban pemrograman. Jika kelihatannya tidak seperti itu, teruslah membacanya sampai selesai :)
Tim Post
15

Selain jawaban penyetelan perangkat keras / pengaturan yang sangat baik dari @jimwise, "linux latensi rendah" menyiratkan:

  • C ++ untuk alasan determinisme (tidak ada penundaan kejutan saat GC masuk), akses ke fasilitas tingkat rendah (I / O, sinyal), kekuatan bahasa (penggunaan penuh TMP dan STL, keamanan jenis).
  • lebih suka kecepatan-over-memori:> 512 Gb RAM adalah umum; basis data ada dalam memori, cache di muka, atau produk NoSQL yang eksotis.
  • pilihan algoritma: as-fast-as-possible versus waras / dapat dimengerti / extensible, mis. bebas-bit, beberapa array bit alih-alih array-of-object-with-bool-properties.
  • penggunaan penuh fasilitas OS seperti Memori Bersama antar proses pada inti yang berbeda.
  • aman. Perangkat lunak HFT biasanya ditempatkan bersama di Bursa Efek sehingga kemungkinan malware tidak dapat diterima.

Banyak dari teknik ini tumpang tindih dengan pengembangan game yang merupakan salah satu alasan mengapa industri perangkat lunak keuangan menyerap programer game yang baru-baru ini berlebihan (setidaknya sampai mereka membayar tunggakan uang sewa).

Kebutuhan mendasar adalah untuk dapat mendengarkan aliran data pasar bandwidth yang sangat tinggi seperti harga sekuritas (saham, komoditas, fx) dan kemudian membuat keputusan beli / jual / lakukan-tidak cepat berdasarkan keamanan, harga dan kepemilikan saat ini.

Tentu saja, ini semua bisa salah secara spektakuler .


Jadi saya akan menguraikan titik array bit . Katakanlah kita memiliki sistem Perdagangan Frekuensi Tinggi yang beroperasi pada daftar Pesanan yang panjang (Beli 5k IBM, Jual 10k DELL, dll). Katakanlah kita perlu menentukan dengan cepat apakah semua pesanan dipenuhi, sehingga kita dapat beralih ke tugas berikutnya. Dalam pemrograman OO tradisional, ini akan terlihat seperti:

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(); } );

kompleksitas algoritmik dari kode ini menjadi O (N) karena merupakan pemindaian linier. Mari kita lihat profil kinerja dalam hal akses memori: setiap iterasi dari loop di dalam std :: any_of () akan memanggil o.isFilled (), yang diuraikan, sehingga menjadi akses memori _isFilled, 1 byte (atau 4 tergantung pada arsitektur Anda, penyusun dan pengaturan penyusun) dalam objek katakanlah total 128 byte. Jadi kita mengakses 1 byte di setiap 128 byte. Ketika kita membaca 1 byte, dengan anggapan kasus terburuk, kita akan kehilangan cache data CPU. Ini akan menyebabkan permintaan baca ke RAM yang membaca seluruh baris dari RAM ( lihat di sini untuk info lebih lanjut ) hanya untuk membaca 8 bit. Jadi profil akses memori sebanding dengan N.

Bandingkan ini dengan:

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); }

profil akses memori dari ini, dengan asumsi kasus terburuk lagi, adalah ELEMS dibagi dengan lebar garis RAM (bervariasi - bisa dual-channel atau triple-channel, dll).

Jadi, sebenarnya, kami mengoptimalkan algoritme untuk pola akses memori. Tidak ada jumlah RAM yang akan membantu - ini adalah ukuran cache data CPU yang menyebabkan kebutuhan ini.

Apakah ini membantu?


Ada CPPCon yang sangat baik berbicara tentang pemrograman latensi rendah (untuk HFT) di YouTube: https://www.youtube.com/watch?v=NH1Tta7purM

JBRWilkinson
sumber
"beberapa bit array bukannya array-of-objek-dengan-bool-properties" apa yang Anda maksudkan dengan ini?
user997112
1
Saya telah menguraikan contoh dan tautan.
JBRWilkinson
Melangkah lebih jauh - daripada menggunakan seluruh byte untuk menunjukkan apakah pesanan dipenuhi atau tidak - Anda bisa menggunakan bit tunggal. Jadi dalam satu cacheline (64 byte) - Anda bisa mewakili keadaan 256 pesanan. Jadi - kurang meleset.
quixver
Juga - jika Anda melakukan pemindaian linear memori - prefetcher perangkat keras melakukan pekerjaan yang baik untuk memuat data Anda. Asalkan Anda mengakses memori secara berurutan atau melangkah atau sesuatu yang sederhana. Tetapi jika Anda mengakses memori dengan cara apa pun yang tidak berurutan - prefetcher CPU menjadi bingung. Misalnya pencarian biner. Pada titik itu programmer dapat membantu cpu dengan petunjuk - _mm_prefetch.
quixver
-2

Karena saya tidak memasukkan satu atau dua perangkat lunak frekuensi tinggi dalam produksi, saya akan mengatakan hal yang paling penting:

  1. Konfigurasi perangkat keras dan administrator sistem bersama-sama dengan insinyur jaringan TIDAK menentukan hasil yang baik dari jumlah pesanan yang diproses oleh sistem perdagangan, tetapi mereka dapat menurunkan waktu yang besar jika mereka tidak tahu dasar-dasar yang diuraikan di atas.
  2. Satu-satunya orang yang benar-benar membuat sistem untuk melakukan perdagangan frekuensi tinggi adalah seorang ilmuwan komputer yang menyatukan kode dalam c ++

    Di antara pengetahuan yang digunakan adalah

    A. Bandingkan Dan Tukar operasi.

    • bagaimana CAS digunakan dalam prosesor dan bagaimana komputer mendukungnya untuk digunakan dalam apa yang disebut pemrosesan struktur Tanpa-Penguncian. Atau Pemrosesan bebas kunci. Saya tidak akan menulis seluruh buku di sini. Singkatnya, kompilator GNU dan kompiler Microsoft mendukung penggunaan langsung instruksi CAS. Ini memungkinkan kode Anda untuk memiliki "No.Wair" saat mengekstraksi elemen dari antrian atau memasukkan yang baru ke dalam antrian.
  3. Ilmuwan berbakat akan menggunakan lebih banyak. Dia harus menemukan "pola" baru yang baru muncul pertama kali di Jawa. Disebut pola DISRUPTOR. Lipatan dalam pertukaran LMAX di Eropa menjelaskan kepada komunitas frekuensi tinggi bahwa pemanfaatan berbasis thread pada prosesor modern akan kehilangan waktu pemrosesan pada rilis cache memori oleh CPU jika antrian daya tidak selaras dengan ukuran cache cpu modern = 64

    Jadi untuk pembacaan itu mereka mempublikasikan kode java yang memungkinkan proses multi-threading untuk menggunakan cache CPU perangkat keras dengan benar tanpa resolusi konflik. Dan ilmuwan komputer yang baik HARUS menemukan pola itu sudah porting ke c ++ atau melakukan porting sendiri.

    Ini adalah cara mahir di luar konfigurasi admin. Ini adalah jantung nyata frekuensi tinggi hari ini.

  4. Ilmuwan komputer HARUS menulis banyak kode C ++ tidak hanya untuk membantu orang QA. Tapi juga
    • memvalidasi di wajah pedagang terbukti kecepatan yang dicapai
    • mengutuk menggunakan teknologi lama yang berbeda dan mengekspos mereka dengan kode sendiri untuk menunjukkan mereka gagal menghasilkan hasil yang baik
    • tulislah sendiri kode multi-threading komunikasi c ++ yang didasarkan pada kecepatan kernel yang telah terbukti / pilih alih-alih menggunakan teknologi yang lama. Saya akan memberi Anda contoh - perpustakaan tcp modern adalah ICE. Dan orang-orang yang melakukannya sangat cerdas. Tetapi prioritas mereka ada di bidang kompabilitas dengan banyak bahasa. Begitu. Anda dapat melakukannya dengan lebih baik di c ++. Jadi cari exaples berkinerja tinggi berdasarkan panggilan pilih ASYNCHRONOUS. Dan jangan pergi untuk banyak konsumen, banyak produsen - bukan untuk HF.
      Dan Anda akan kagum mendapati bahwa pipa HANYA HANYA UNTUK pemberitahuan kernel tentang pesan yang diterima. Anda dapat memasukkan nomor pesan 64-bit di sana - tetapi untuk konten Anda mendatangi Anda antrian CAS yang tidak dikunci. Dipicu oleh select()panggilan kernel asinkron .
    • bahkan. Pelajari tentang menetapkan dengan afinitas c ++ utas ke utas Anda yang melakukan pemipaan / antrian pesan Anda. Utas itu harus memiliki afinitas inti. Tidak ada orang lain yang harus menggunakan nomor inti CPU yang sama.
    • dan seterusnya.

Seperti yang Anda lihat - frekuensi tinggi adalah LAPANGAN PENGEMBANGAN. Anda tidak bisa hanya menjadi programmer C ++ untuk berhasil.

Dan ketika saya mengatakan untuk berhasil, saya maksudkan bahwa dana lindung nilai yang Anda akan bekerja untuk AKAN mengenali upaya wisata dalam kompensasi tahunan di luar jumlah yang dibicarakan orang dan perekrut.

Masa-masa sederhana konstruktor / destruktor FAQ hilang selamanya. Dan c ++ ... itu sendiri dimigrasikan dengan kompiler baru untuk membebaskan Anda dari manajemen memori dan untuk menegakkan tidak ada warisan kedalaman besar di kelas. Buang-buang waktu. Paradigma penggunaan kembali kode berubah. Ini bukan hanya tentang berapa banyak kelas yang Anda buat dalam polimorf. Ini adalah tentang kinerja waktu kode yang dikonfirmasi lurus yang dapat Anda gunakan kembali.

Jadi itu pilihan Anda untuk mempelajari kurva belajar di sana, atau tidak. Itu tidak akan pernah mencapai tanda berhenti.

alex p
sumber
6
Anda mungkin ingin berupaya mengeja dan memformat. Dalam bentuknya saat ini, pos ini nyaris tidak dapat dipahami.
CodesInChaos
1
Anda menggambarkan situasi 10 tahun yang lalu. Solusi berbasis perangkat keras dengan mudah mengungguli C ++ murni saat ini, tidak peduli seberapa optimal C ++ Anda.
Sjoerd
Bagi mereka yang ingin tahu apa itu solusi berbasis perangkat keras - itu sebagian besar solusi FPGA di mana kode sebenarnya dibakar ke dalam memori cepat dan tidak berubah tanpa reburning dari apa yang disebut memori ROM. Baca Saja
alex p
@alexp Anda jelas tidak tahu apa yang Anda bicarakan. FPGA adalah sesuatu yang berbeda dari "kode yang dibakar dalam memori cepat."
Sjoerd