Pull to refresh
65
-1.3
Свистунов Сергей @svistunov

Технический менеджер

Send message

Это же всё предполагает запуск на сервере, а наличие собственного внутреннего языка ещё больше ограничивает участников/ Здесь идея абсолютно противоположная, у игроков есть все технологии мира, а внутренним языком, в принципе, можно считать API.

Странно, но этот вариант выигрывает у CopyUnsafeV2

BenchmarkCopyUnsafeV2-16           	   68326	     84459 ns/op	       0 B/op	       0 allocs/op
BenchmarkCopyUnsafeV3-16           	   80085	     75279 ns/op	       0 B/op	       0 allocs/op

, но проигрывает в Unrolled варианте:

BenchmarkCopyUnrolledLoop4-16      	  103786	     55923 ns/op	       0 B/op	       0 allocs/op
BenchmarkCopyUnrolledLoop4v2-16    	   96066	     61919 ns/op	       0 B/op	       0 allocs/op

Хотя ассемблер выглядит чище 🤔

Я нашёл способ как ещё в 2 раза ускорить копирование одной картинки в другую, пошёл статью писать

Если пользоваться стандартным декодером, то RGBA, но в сыром виде в тестовых картинках - RGB.

Вообще было 5 дней, но по факту у меня было 3 вечера, я поздно увидел письмо о новой задаче и основную работу никто не отменял.

В Go можно использовать асскмблер, но быстрого решения как с помощью AVX команд вынуть каждый 3 байт я не нашёл, есть идеи как это сделать?

Если придумаем как. Тут есть ряд проблем:

  1. Если открыть решения, то остальные его будут просто отправлять лучшее под своим аккаунтом. Смысл leaderboard'а пропадёт.

  2. Не все участники хотят раскрывать свои решения, по опросам где-то 50% участников.

Были мысли ограничить время на отправку решений, допустим 30 дней от первой попытки, а после этого срока показывать решения других участников, которые хотят поделиться своим кодом. Но тут появляется большая дыра, никто не мешает завести несколько аккаунтов.

При наличии своих DevOps и Infra нет смысла в моей платформе, она для тех, кто не хочет их нанимать, это дорого. Бизнес разработка должна пилить фичи, а не думать об инфраструктуре.
Распределение — автоматическое.

Runner'ы обмениваются информацией о состоянии друг друга и на основе этих данных принимается решение о вероятности выбора инстанса для запроса. Т.е. вероятность попасть на более близкий и свободноный инстанс выше, чем нам более дальний или занятный.

Метрики — это приборы, без которых летать нельзя :)
В начале статьи под спойлером текст
Хотелось максимально полного контроля: что написал, то и получил.
Действительно есть, я был уверен, что он есть только на Xeon'ах:
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp flush_l1d
Значит будет продолжение, с использованием AVX.
1) Да, в соответствии с рекомендацией github.com/google/benchmark#disable-cpu-frequency-scaling
2) AVX нет на десктопных CPU, но думаю, что его использование может ещё ускорить.
3) Распараллеливание — это всё же другой подход, при условии, что все ядра загружены, от распараллеливания не будет выгоды.
То, что компилятор «додумался» сделать на маленькой программке, совсем не гарантирует того, что он это сделает на большой. Поэтому лучше самому понимать, как писать более оптимальные варианты.
Например в варианте BM_SSE_COUNT_LOADU компилятор дополнительно раскрывает цикл на 4 итерации, но не делает это для BM_SSE_COUNT_SET_EPI.
           cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr)));
  401040:       c5 f9 75 0c 48          vpcmpeqw (%rax,%rcx,2),%xmm0,%xmm1
  401045:       c5 f9 d7 f1             vpmovmskb %xmm1,%esi
  401049:       f3 0f b8 f6             popcnt %esi,%esi
  40104d:       48 01 d6                add    %rdx,%rsi
  401050:       c5 f9 75 4c 48 10       vpcmpeqw 0x10(%rax,%rcx,2),%xmm0,%xmm1
  401056:       c5 f9 d7 d1             vpmovmskb %xmm1,%edx
  40105a:       f3 0f b8 d2             popcnt %edx,%edx
  40105e:       48 01 f2                add    %rsi,%rdx
  401061:       c5 f9 75 4c 48 20       vpcmpeqw 0x20(%rax,%rcx,2),%xmm0,%xmm1
  401067:       c5 f9 d7 f1             vpmovmskb %xmm1,%esi
  40106b:       f3 0f b8 f6             popcnt %esi,%esi
  40106f:       c5 f9 75 4c 48 30       vpcmpeqw 0x30(%rax,%rcx,2),%xmm0,%xmm1
  401075:       48 01 d6                add    %rdx,%rsi
  401078:       c5 f9 d7 d1             vpmovmskb %xmm1,%edx
  40107c:       f3 0f b8 d2             popcnt %edx,%edx
  401080:       48 01 f2                add    %rsi,%rdx
Например метод Dial из библиотеки grpc имеет почти 30 аргументов: godoc.org/google.golang.org/grpc#DialOption
Выглядит так, что если ничего не делать, то не ошибёшься и получишь всю премию.
Здесь важно было только то, что путь начинается с /users, т.к. дальше возможны варианты:
  • /users/1
  • /users/1/visits
  • /users/zfsdfasdadsdf

Это всё уже внутри handleGetUser()
handleGetUser
void Connection::handlerGetUser() {
    char *endptr;
    auto id = strtol(path.Data + 7, &endptr, 10);

    if (endptr[0] != 0 && endptr[0] != '/') {
        WriteNotFound();
        return;
    }

    if (id >= USERS_CNT || db.users[id].Fields == 0) {
        WriteNotFound();
        return;
    }

    if (endptr[0] == 0) {
        db.users[id].MarshalJSON(outBuf);
        WriteResponse();
        return;
    }

    if (strncmp(endptr, "/visits", 7) != 0) {
        WriteNotFound();
        return;
    }

    uint64_t fromDate = 0;
    uint64_t toDate = 0;
    char country[101];
    country[0] = 0;
    uint64_t toDistance = 0;

    endptr += 7;
    while (true) {
        switch (endptr[0]) {
        case '?':
        case '&':
            ++endptr;
            break;
        }

        if (endptr[0] == 0) {
            break;
        } else if (strncmp(endptr, "fromDate=", 9) == 0) {
            fromDate = strtol(endptr + 9, &endptr, 10);
        } else if (strncmp(endptr, "toDate=", 7) == 0) {
            toDate = strtol(endptr + 7, &endptr, 10);
        } else if (strncmp(endptr, "country=", 8) == 0) {
            endptr += 8;
            auto pos = strchr(endptr, '&');
            if (pos != NULL) {
                pos[0] = 0;
                percent_decode(country, endptr);
                pos[0] = '&';
                endptr = pos;
            } else {
                percent_decode(country, endptr);
                break;
            }
        } else if (strncmp(endptr, "toDistance=", 11) == 0) {
            toDistance = strtol(endptr + 11, &endptr, 10);
        } else {
            WriteBadRequest();
            return;
        }
    }

    outBuf.Append("{\"visits\":[");
    auto first = true;

    for (auto it = db.users[id].visits->cbegin();
            it != db.users[id].visits->cend(); ++it) {
        if ((fromDate == 0 || db.visits[*it].VisitedAt > fromDate)
                && (country[0] == 0
                        || strcmp(db.locations[db.visits[*it].Location].Country,
                                country) == 0)
                && (toDistance == 0
                        || toDistance
                                > db.locations[db.visits[*it].Location].Distance)) {

            if (toDate != 0 && db.visits[*it].VisitedAt > toDate) {
                break;
            }

            if (!first) {
                outBuf.Append(",{\"mark\":");
            } else {
                first = false;
                outBuf.Append("{\"mark\":");
            }

            outBuf.AddLen(
                    hl_write_string(uint64_t(db.visits[*it].Mark), outBuf.End));

            outBuf.Append(",\"visited_at\":");
            outBuf.AddLen(
                    hl_write_string(db.visits[*it].VisitedAt, outBuf.End));

            outBuf.Append(",\"place\":\"");
            outBuf.Append(db.locations[db.visits[*it].Location].Place);
            outBuf.Append("\"}");
        }
    }

    outBuf.Append("]}");

    WriteResponse();
}

1

Information

Rating
Does not participate
Location
Lisboa, Португалия
Date of birth
Registered
Activity

Specialization

Chief Technology Officer (CTO)
Lead