ФлеймФорумПрограммирование

[Russian AI Cup] CodeWars 2017 (6 стр)

Страницы: 15 6 7 811 Следующая »
#75
0:14, 15 ноя 2017

ud1
> Ну видно, что они долго оптимизировали.

int RemoteProcessClient::readInt() {
    vector<signed char> bytes = this->readBytes(INTEGER_SIZE_BYTES);

    if (this->isLittleEndianMachine() != LITTLE_ENDIAN_BYTE_ORDER) {
        reverse(bytes.begin(), bytes.end());
    }

    int value;
    memcpy(&value, &bytes[0], INTEGER_SIZE_BYTES);
    return value;
}

запустил профайлер:
read lead to a lot of sys calls | [Russian AI Cup] CodeWars 2017
std::vector eat half of cputime in this method | [Russian AI Cup] CodeWars 2017

ЗЫ: судя по первой картинке можно подумать: либо с java стороны байты по одной штуке приходят, либо на стороне с++ каждый раз буфер размером в 100кб создаётся just for lulz.

added: если бы я делал протокол и мне не мешали, то я бы старался за два syscall`а получать PlayerContext.

#76
0:37, 15 ноя 2017

Adler
> ЗЫ: судя по первой картинке можно подумать: либо с java стороны байты по одной
> штуке приходят, либо на стороне с++ каждый раз буфер размером в 100кб создаётся
> just for lulz.
Где 100Кб? Посмотрел, byteCount передается ровно столько, сколько хотят прочесть. И насколько помню со старых контестов, со стороны жавы тоже нормально передавали, сразу сообщение целиком, не по байту. Код конечно можно еще облагородить, но в целом вроде норм.

#77
1:25, 15 ноя 2017

counter воткнул:

int32 CSimpleSocket::Receive(int32 nMaxBytes)
{
...
    if ((m_pBuffer != NULL) && (nMaxBytes != m_nBufferSize))
    {
        static int counter=0;counter++; // <------------------------- этот = 395856/209 = 1894.04 за кадр в среднем
        delete [] m_pBuffer;
        m_pBuffer = NULL;
    }
...
    switch (m_nSocketType)
    {
        case CSimpleSocket::SocketTypeTcp:
        {
            do 
            {
                static int counter=0;counter++;  // <------------------------- этот = 649411/209 = 3107.22 за кадр в среднем
                m_nBytesReceived = RECV(m_socket, (m_pBuffer + m_nBytesReceived), 
                                        nMaxBytes, m_nFlags);


                TranslateSocketError();
            } while ((GetSocketError() == CSimpleSocket::SocketInterrupted));

            break;
        }
...

RECV - это recv из Winsock2.h

они тут m_pBuffer пересоздают каждый раз когда надо что-то прочитать другого размера.

also: RemoteProcessClient::readBytes вызывается 494891/209=2367.89 раз за кадр в среднем.

итого:
выделений памяти: 1894+2367 = 4261 раз за кадр
вызов recv: 3107 раз за кадр  // вместо двух, если бы всё было сделано идеально. да, на стороне java надо было бы посчитать весь размер заранее, но это должно быть быстрее чем делать дополнительные системные вызовы send/recv.

ЗЫ: ещё воткнул "static int recv_n=0;recv_n+=m_nBytesReceived>0?m_nBytesReceived:0;" в конец CSimpleSocket::Receive
результат: 2963076/209 = 14177.39 байт за кадр.

upd:
оптимизировал readVehicleUpdate

+ Показать

upd:
замерил среднее время выполнения readVehicleUpdates:
до: 6.55 ms/frame
после: 3.69 ms/frame

#78
2:37, 15 ноя 2017

ud1
> И насколько помню со старых контестов, со стороны жавы тоже нормально
> передавали, сразу сообщение целиком, не по байту. Код конечно можно еще
> облагородить, но в целом вроде норм.
смотри, в среднем за кадр надо прочитать 14177.39 байт, но для этого делается 3107 системных вызов recv, то есть в среднем читается по 4.56 байта за один вызов recv.

это не нормально.

#79
15:06, 15 ноя 2017

короче, я зафиксировал seed в "local-runner.default.properties", затем отрыл свою стратегию которая:
  выделяет все юниты
  добавил их в группу 42
  приказывает им вращаться вокруг центра карты

а потом замерил среднее время выполнения readVehicleUpdates для 128 первых кадров: 31.4 ms/frame

стратегии вроде разрешено в среднем тратить только 20ms/frame

полностью переписал readVehicleUpdate:

VehicleUpdate RemoteProcessClient::readVehicleUpdate() {
    if(bool original_version=false)
    {
      if (!readBoolean()) {
          exit(20013);
      }

      long long id = readLong();
      double x = readDouble();
      double y = readDouble();
      int durability = readInt();
      int remainingAttackCooldownTicks = readInt();
      bool selected = readBoolean();//*/

      vector<int> groups = readIntArray();
      return VehicleUpdate(id, x, y, durability, remainingAttackCooldownTicks, selected, groups);
    }

    #define LIST(ADD)\
    ADD(bool,ok,$)\
    ADD(long long,id,$)\
    ADD(double,x,$)\
    ADD(double,y,$)\
    ADD(int,durability,$)\
    ADD(int,remainingAttackCooldownTicks,$)\
    ADD(bool,selected,$)
    //===
    struct t_tmp{
      bool trash_bef[8-1];
      #define F(TYPE,NAME,VALUE)TYPE NAME;
      LIST(F);
      #undef F
      bool groups_size[8-1];
    };
    int size=sizeof(t_tmp)-(8-1)*2+4;
    t_tmp tmp={0};

    //
    if(bool need_fast_networking=true)
    {
      unsigned int offset=0;
      auto m_pBuffer=(char*)&tmp.ok;

      for(;;)
      {
        if(offset>=size)break; 
        auto receivedByteCount=recv(socket.m_socket,m_pBuffer+offset,size-offset,socket.m_nFlags);
        //socket.Receive(size-offset);
        if(receivedByteCount<=0)break;
        offset+=receivedByteCount;
      }
    
      if(offset!=size){
        exit(10012);
      }
    }

    #define F(TYPE,NAME,VALUE)auto&##NAME=tmp.NAME;
    LIST(F);
    #undef F
    #undef LIST
    
    if(!ok)exit(20013);

    vector<int> groups;groups.resize(*(int*)&tmp.groups_size);

    if(bool need_fast_networking=true)if(!groups.empty())
    {
      int size=groups.size()*4;
      unsigned int offset=0;
      auto m_pBuffer=(char*)&groups[0];

      for(;;)
      {
        if(offset>=size)break; 
        auto receivedByteCount=recv(socket.m_socket,m_pBuffer+offset,size-offset,socket.m_nFlags);
        if(receivedByteCount<=0)break;
        offset+=receivedByteCount;
      }
    
      if(offset!=size){
        exit(10012);
      }
    }

    return VehicleUpdate(id, x, y, durability, remainingAttackCooldownTicks, selected, groups);
}

у меня этот код работает на этом же тесте в среднем за 3.9ms/frame для 128 первых кадров.

+ Показать

ЗЫ: ещё я "оптимизировал" StatTimer.h: https://pastebin.com/zBjiHByb

#80
15:28, 15 ноя 2017

Мне кажется на данный момент самая лучшая стратегия у GreanTea http://russianaicup.ru/profile/GreenTea
Квадратно-гнездовой способ битвы его стратегии проигрывает в чистую.

#81
16:48, 15 ноя 2017

похоже инфа о том, кто что выделил и какой юнит в каких группах находиться присылается даже про оппонента.

added:
отправил pull request: https://github.com/Russian-AI-Cup-2017/cpp-cgdk/pull/3

#82
18:51, 15 ноя 2017

Diversus
Да неплохо, но имхо тут ЯУ рашит не фиго, зря добавили

#83
19:12, 15 ноя 2017

Adler
> отправил pull request: https://github.com/Russian-AI-Cup-2017/cpp-cgdk/pull/3
  Надеюсь у них всё не так плохо с ревью кода, чтобы это прошло в продакшн.

+ Показать
#84
20:09, 15 ноя 2017

ЕПРСТ объясните как пашет Scale плиз, а то из прввил не фига не въехал
UPD все разобрался я затупок команду перекрывал следующей за ней идущей

#85
22:19, 15 ноя 2017

Что-то я не пойму, как перебрать свою технику в цикле?
Только через VechicleUpdate? А там и своя и чужая техника, или как?

#86
23:29, 15 ноя 2017

Diversus
GetNewVehicles - содержит не изменяемые параметры "новой" техники в игре
Т.е. в начале игры этот вызов делается в тике 0 мы получаем всю существующую технику в игре (включая свою, и вражескую разница в PlayerID) (Так же как я понял в режиме "туман войны", вражеская техника в этот массив не попадает, а появляется в случае обнаружения). Так же технику с 0 здоровьем можно смело затирать
Далее по ходу игры вызываешь GetVehicleUpdates оно содержит изменяемые поля (x,y, здоровье, ну и ID техники ессесно) 
По ID техники присваиваешь новые параметры своему массиву данных. Как-то так

#87
19:29, 16 ноя 2017

сначала оптимизируешь время работы стратегии где вся тысяча объектов движется все 20000 кадров.
потом находишь тормозное говно в сетевой части стратегии.
исправляешь его.
отправляешь pull request
ждешь.
а потом тебе заявляют:

Мы не принимаем правки в автогенерённый код, так как их невозможно поддерживать в случае изменения клиента. Время работы пустой стратегии на C++ составляет всего несколько секунд при общем лимите в 210 секунд. Подобный уровень оптимизации излишен.

> Время работы пустой стратегии на C++
WTF?

ответил им:

вот в этой игре:
http://russianaicup.ru/game/view/30740

я использовал вот эту стратегию:
https://pastebin.com/raw/Npqqs1m4

посмотрите на время:
time consumed: 84.12 sec
time passed: 242.33 sec
peak memory: 4874240 bytes

что скажите?

PS: им придёт уведомление на комментарий в закрытом pull request`е? или это тоже самое что в /dev/null отправить?

#88
21:00, 16 ноя 2017

Adler
Ща чую ты добьешся от них того, что число групп уменьшат. До 5 например.

#89
22:16, 16 ноя 2017

Adler
Вот моя оптимизация, проверь, насколько стало быстрее:
https://github.com/Russian-AI-Cup-2017/cpp-cgdk/pull/5

Страницы: 15 6 7 811 Следующая »
ФлеймФорумПрограммирование

Тема в архиве.