Every saga has a beginning...
- в пике - 1000 подключений
- С++ / потоки
- утечки памяти
* thread #2: tid = 0x3103, 0x000000010003bf2b libcurl.dylib`Curl_pp_readresp(sockfd=4, pp=0x0000000100806508, code=0x0000000100780ad4, size=0x0000000100780b20) + 794 at pingpong.c:379, stop reason = EXC_BAD_ACCESS (code=1, address=0x102800000)
frame #0: 0x000000010003bf2b libcurl.dylib`Curl_pp_readresp(sockfd=4, pp=0x0000000100806508, code=0x0000000100780ad4, size=0x0000000100780b20) + 794 at pingpong.c:379
frame #1: 0x0000000100011e43 libcurl.dylib`http_readresp(, httpcode=0x0000000100780b8c) + 29 at http.c:627
frame #2: 0x0000000100011dab libcurl.dylib`Curl_GethttpResponse(nreadp=0x0000000100780b90, conn=0x0000000100806000) + 227 at http.c:759
frame #3: 0x00000001000115ec libcurl.dylib`http_done [inlined] http_sendquote(, conn=0x0000000100806000) + 86 at http.c:3530
frame #4: 0x0000000100011596 libcurl.dylib`http_done(conn=0x0000000100806000, status=CURLE_OK, premature=false) + 1258 at http.c:3485
frame #5: 0x000000010001c8ed libcurl.dylib`Curl_done(connp=0x0000000101a00038) + 271 at url.c:5425
frame #6: 0x0000000100029eae libcurl.dylib`multi_runsingle(multi=0x0000000100600000, now=(null), easy=0x0000000101a00020) + 1580 at multi.c:1577
frame #7: 0x000000010002b0ee libcurl.dylib`multi_socket(multi=0x0000000100600000, checkall=true, s=-1, running_handles=0x0000000100780d94) + 420 at multi.c:2194
frame #8: 0x000000010002b180 libcurl.dylib`curl_multi_socket_action(multi_handle=0x0000000100600000) + 27 at multi.c:2297
frame #9: 0x000000010000126a crashtest`curl_perform_action(socket=-1, actions=0) + 42 at multi-gcd-crashtest.c:101
frame #10: 0x000000010000209d crashtest`__create_timeout_block_invoke(.block_descriptor=0x0000000100003210) + 29 at multi-gcd-crashtest.c:167
frame #11: 0x00007fff995710b6 libdispatch.dylib`_dispatch_client_callout + 8
frame #12: 0x00007fff9957329b libdispatch.dylib`_dispatch_source_invoke + 691
frame #13: 0x00007fff99572305 libdispatch.dylib`_dispatch_queue_invoke + 72
frame #14: 0x00007fff99572448 libdispatch.dylib`_dispatch_queue_drain + 180
frame #15: 0x00007fff995722f1 libdispatch.dylib`_dispatch_queue_invoke + 52
frame #16: 0x00007fff995721c3 libdispatch.dylib`_dispatch_worker_thread2 + 249
frame #17: 0x00007fff99731d0b libsystem_c.dylib`_pthread_wqthread + 404
frame #18: 0x00007fff9971c1d1 libsystem_c.dylib`start_wqthread + 13
Типичный день на сервере
-
Сервер перестал падать
- Память перестала исчезать в никуда
- Производительность:
меньше в ~3 раза - Простота поддержки:
БЕСЦЕННО
2600
178
127
134
345
DISCLAIMER
Response time
Пульс GC
getFakeHistory = function (size) {
//generate 20kb of data
};
function Record (id, description) {
this.id = id;
this.description = description;
}
Record.prototype.doMagic = function () {
return this.id + 1;
}
var sum = 0;
for (var i = 0; i < 10000; i++) {
console.time('create');
var record = new Record(i, getFakeHistory(20 * 102400));
sum += record.doMagic();
console.timeEnd('create');
}
console.log('//' + sum);
New
Old
Large Object
NEW
- от 1 до 8Mb
- быстрое выделение памяти
OLD
- Хранится страницами по 1Mb
- mark-sweep, mark-compact
var sum = 0;
var records = [];
for (var i = 0; i < 10000; i++) {
records[i] = new Record();
}
for (var i = 0; i < 10000; i++) {
console.time('create');
var record = records[i].set(1, getFakeHistory(20 * 102400));
sum += records[i].doMagic();
console.timeEnd('create');
}
console.log('//' + sum);
До
После
[большие массивы]
var MAX_PLAYER_ID = 10000;
var data = new Array(MAX_PLAYER_ID);
var sum = 0;
console.time('access');
for (var i = 0; i < 10000000; i++) {
var pos = ~~(Math.random() * MAX_PLAYER_ID);
if (typeof data[pos] === 'undefined') {
data[pos] = 1;
} else {
data[pos]++;
}
}
console.timeEnd('access');
data.reduce(function (sum, e) { return sum + parseInt(e, 0); }, 0);
100 / 111ms
1000 / 115ms
10000 / 123ms
99999
137ms
100000
258ms
--allow-natives-syntax
function hasFastElements(obj) {
return %HasFastSmiElements(obj) ||
%HasFastSmiOrObjectElements(obj) ||
%HasFastObjectElements(obj) ||
%HasFastDoubleElements(obj) ||
%HasFastHoleyElements(obj);
}
Массивы
- Fast Elements / Dictionary Elements
- delete может переключить режим
- Преаллокация массива быстрее
- Кроме больших массивов >100k элементов
- Обращение к неинициализированным элементам - 2х затраты по производительности
var MAX_PLAYER_ID = 100000;
var data = [];
for (var i = 0; i < MAX_PLAYER_ID; i++) {
data.push(0);
}
100000
258ms
137ms
По следам Кнута
function Player (id) {
this.name = 'SomeName';
//...
}
Player.prototype.setPremium(premiumInfo) {
this.premium = true;
this.premiumInfo = premiumInfo
}
var player = new Player(123);
players.push(player);
//...
if (PremiumChecker.isPremium(player)) {
player.setPremium(PremiumChecker.getPremiumInfo(player));
setTimeout(removePlayerFn(player), 3600); // delete players[i]
}
v8: что внутри
Скрытые классы
function Point(x, y) {
this.x = x;
this.y = y;
}
Full
- Мгновенно запускает код
- Не делает предположений о типах данных
- Использует "Inline Cache" для улучшения производительности на лету
Optimizing
- Вызывается только для "горячих" функций
- Выводит типы из "Inline cache"
- Пытается выполнить inline всего что только можно
Два компилятора
А как же asm.js?
call = $$$
Никаких call
this.premium = true;
Boxing
edsds
Легкие способы выстрелить себе в ногу
- Объекты разных типов в массиве (возможно даже скрытых)
- Нарушение мономорфности
- delete players[i]
- try / catch - не оптимизируется никогда
- Удивить engine
"Not optimized: Optimized too many times"
Найти и обезвредить
No DOM
No libraries
No ideas
--trace_opts --trace_deopts
[marking 0x31bfb004bc29 <JS Function random (SharedFunctionInfo 0x31bfb00398b1)>
for recompilation, reason: small function, ICs with typeinfo: 31/31 (100%), generic ICs: 0/31 (0%)]
took 0.043, 0.180, 0.054 ms]
[marking 0x244913034d19 <JS Function (SharedFunctionInfo 0x244913023ca9)> for recompilation
reason: hot and stable, ICs with typeinfo: 16/25 (64%), generic ICs: 0/25 (0%)]
Hot & Stable - мечта любого JS-engine
То же и в Chrome
"Not optimized: ForInStatement is not fast case"
for (var prop in obj) {
/* много-много-кода */
}
function f(p) {
/* много кода */
}
for (var prop in obj) {
f(prop);
}
Не оптимизируется :(
- Генераторы
- for-of
- try-catch
- try-finally
- let и сompound assignment ( let a = 3; a += 2; )
- proto, get, set
FDConf #15 Медленный JS
By Illya Klymov