Задача оптимизации кода на С

Тема в разделе "WASM.A&O", создана пользователем XJess, 21 фев 2009.

  1. XJess

    XJess New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2009
    Сообщения:
    4
    Привет всем!
    Дали мне тут задачу по оптимизации кода, а я такими вещами никогда раньше не занималась, поэтому решила спросить у коллег. Код дан ниже. Условия такие: есть межсетевой экран, через который проходит трафик, по этому трафику собирается статистика в определенный массив. Функция GetUserShow, которую надо оптимизировать, как раз собирает эту статистикиу. Но в соединении может участвовать не только компьютер, характеризующийся IP-адресом, но и так называемый VPN-клиент, который характеризуется определенным номером, а не IP-адресом (либо с той, либо с другой стороны соединения). Таким образом, есть 3 варианта соединения:
    IP-адрес — IP-адрес
    IP-адрес — VPN-клиент
    VPN-клиент — IP-адрес

    Так вот, эта функция получает данные о трафике и проверяет полным перебором по массиву usershow; если нет записи для данной пары отправитель-получатель, то она добавляется в массив; если массив полон (максимальная длина — MAXABONENT), то удаляется самая старая, добавляется новая; если такая запись уже есть, то не добавляется. Кстати, надо учесть, что может придти такая пара (адреса условно обозначены цифрами):
    100 — 101
    и такая пара
    101 — 100

    И они считаются одинаковыми, это тоже надо учитывать.

    Так вот, надо постараться оптимизировать код функции как можно лучше. Я, конечно, понимаю, что полный перебор — это плохо, и можно взять какой-то другой алгоритм поиска и получить выигрыш в скорости, но хотелось бы услышать мнение более опытных людей, какой именно алгоритм можно было бы задействовать и почему(!) — обязательно аргументируйте. Может, в коде еще что-то можно оптимизировать. Любым предложениям по потимизации буду рада, потому что не знаю пока, с какого ркая грызть эту задачу. Кстати, многие поля структур можно игнорировать, они несущественны, имеют значение только вот эти 4 поля (по крайней мере, так мне объяснили):

    Код (Text):
    1. saddr =acc->ac_souraddr;     daddr  =acc->ac_destaddr;
    2. sclient=acc->ac_localclient; dclient=acc->ac_remoteclient;
    Эти поля выступают также как флаги, показывающие, какой из трех случаев имеет место.

    Примерный код ниже (примерный, потому что некоторые вещи не существенны):

    Код (Text):
    1. typedef void guardworktype;
    2. typedef void clientworktype;
    3.  
    4. typedef unsigned char   BYTE; //  8 бит
    5. typedef unsigned short  WORD;   // 16 бит
    6. typedef unsigned long   DWRD;   // 32 бита
    7.  
    8. typedef struct _ptype_ {
    9.     WORD pt_portnumber;
    10. };
    11.  
    12. DWRD curftime;
    13. DWRD curtick;
    14. const static int TIMELIVEABONENT = 20;
    15.  
    16. typedef struct {
    17.   DWRD   ac_souraddr; // адрес отправителя (в глобальном формате)
    18.   struct _gwtype_ *ac_localguard; // ссылка на гадюку отправителя(0-нет)
    19.   struct _ptype_  *ac_recvport; // порт откуда принят пакет
    20.   struct _cliwrk_ *ac_localclient;
    21.   DWRD   ac_destaddr; // адрес получателя
    22.   struct _gwtype_ *ac_destguard;        // ссылка на гадюку получателя(0-нет)
    23.   struct _ptype_  *ac_linkport; // порт куда необходимо послать пакет
    24.   struct _cliwrk_ *ac_remoteclient;
    25.   DWRD   ac_lendata; // размер данных в принятом пакете
    26.   BYTE   ac_ipheadlen; // размер IP заголовка в данном пакете
    27.   BYTE   ac_ipprotocol; // протокол в IP
    28.   BYTE   ac_direct;
    29.   BYTE   ac_ipflags; // флаги из IP пакета
    30.   WORD   ac_sourport; // TCP/UDP порты (должны быть вместе)
    31.   WORD   ac_destport;         // *(DWRD*)&ac_sourport==0 - не определены
    32.   DWRD   ac_reccrylendata; // размер данных до преобразования на приеме
    33.   DWRD   ac_reclendata; // размер данных после преобразования на приеме
    34.   DWRD   ac_senlendata; // размер открытых данных на передачу
    35.   DWRD   ac_sencrylendata; // размер закрытых данных на передачу
    36.   BYTE   ac_ipuserprotocol; // протокол в IP оригинальный (как пришел)
    37.   BYTE   ac_routeraccess; // 0/1/2-абоненты/к рутеру/от рутера
    38.   BYTE   ac_statdontupdate; // ACSDU.. не отписывать в статистику и
    39. //отображение
    40.      // на экране - ICMP ERROR MESSAGE
    41.   BYTE   ac_state; // ACS_...
    42.   DWRD   ac_sendmtu; // MTU с каким передавить пакеты в линк
    43. //  DWRD   ac_specialsendmtu; // если длинный пакет с DONTFRAGMENT
    44. // // был принят через фпсу то попытайся
    45. // // передать пакет с таким mtu
    46.   //ipheadertype    *ac_pack;             // сам IP пакет с заголовком
    47.   DWRD             ac_sendtoipaddr; // IP в который отправлять далее
    48.      //  =0 - отправь broadcast
    49.   //DWRD   ac_tcpudpiface[MAXACC/32]; // для TCP/UDP каким группам он
    50. //должен удовлетворить
    51.   //useritemtype    *ac_localuser; // ссылка на юзера отправителя
    52.   //useritemtype    *ac_remoteuser; // ссылка на юзера получателя (0-нет)
    53.   struct _gawwrk_ *ac_localgate; // ссылка на рутер со стороны приема
    54.   struct _gawwrk_ *ac_remotegate; // ссылка на рутер со стороны передачи
    55.   BYTE   ac_backhaddr[6]; // Hardware Address откула пришел
    56.   BYTE   ac_align[2];
    57. } accesstype;
    58.  
    59. #define MAXABONENT     (2048)
    60.  
    61. // биты в поле ab_status
    62. #define ABS_DECLARED    0x01    // запись заполнена
    63. #define ABS_CLOSED    0x02    // запись закрыта
    64. #define ABS_INVRSB    0x04    // счетчик ab_recvsourbytes перехлестнулся
    65. #define ABS_INVRDB    0x08    // счетчик ab_recvdestbytes перехлестнулся
    66. #define ABS_INVRSP    0x10    // счетчик ab_recvsourpack перехлестнулся
    67. #define ABS_INVRDP    0x20    // счетчик ab_recvdestpack перехлестнулся
    68. #define ABS_INVISP    0x40    // счетчик ab_ignoresourpack перехлестнулся
    69. #define ABS_INVIDP    0x80    // счетчик ab_ignoredestpack перехлестнулся
    70.  
    71. typedef struct {
    72.   BYTE               ab_status;        //   0 состояние (ABS_...)
    73.   BYTE             ab_port;        //   1 LAN порт источника (0-не определен)
    74.   BYTE             ab_linkport;        //   2 LAN порт получателя(0-не определен)
    75.   BYTE               ab_nextlist;        //   3
    76.   DWRD               ab_souripaddr;    //   4 IP адрес по стороне ab_port
    77.   DWRD               ab_destipaddr;    //   8 IP адрес по стороне ab_linkport
    78.   guardworktype   *ab_guard;        //  12 гадюка по стороне ab_port (0-открытое)
    79.   guardworktype   *ab_linkguard;        //  16 гадюка по стороне ab_linkport (0-открытое)
    80.   clientworktype  *ab_client;        //     клиент по стороне ab_port
    81.   clientworktype  *ab_linkclient;    //     клиент по стороне ab_linkport
    82.   DWRD               ab_lasttime;        //  20 время прошлого обмена (ftime)
    83.   DWRD               ab_closetime;    //  24 время закрытия записи (ftime)
    84.                     //     (если не закрыта-тики когда сессия закроется)
    85.   DWRD             ab_recvsourbytes;    //  28 кол-во принятых байт от ab_port
    86.   DWRD             ab_recvdestbytes;    //  32 кол-во принятых байт от ab_linkport
    87.   DWRD             ab_recvsourpack;    //  36 кол-во принятых пакетов от ab_port
    88.   DWRD             ab_recvdestpack;    //  40 кол-во принятых пакетов от ab_linkport
    89.   DWRD             ab_ignoresourpack;    //  44 кол-во принятых пакетов от ab_port
    90.   DWRD             ab_ignoredestpack;    //  48 кол-во принятых пакетов от ab_linkport
    91.   DWRD           ab_timesave;        //  52 время на сохранение
    92.   DWRD             ab_initipaddr;    // ip инициатора соединения
    93.   //BYTE           ab_statrec[SIZEUSERSTAT];
    94. //  userfpsuworktype ab_statrec;        //  56 запись статистики (набольшая по длине)
    95.   //histlisttype     ab_errlist[MAXHLIST];//     история ошибок передачи/приема
    96. } usershowtype;                //
    97.  
    98.  
    99. usershowtype         usershow[MAXABONENT];
    100.  
    101. static usershowtype *GetUserShow(accesstype *acc) {
    102.   DWRD          minlast=0xFFFFFFFF,minclose=0xFFFFFFFF;
    103.   usershowtype *uslast=0;
    104.   usershowtype *usclosed=0;
    105.   usershowtype *us=&usershow[0];
    106.  
    107.   DWRD           saddr,daddr;
    108.   clientworktype *sclient,*dclient;
    109.  
    110.   int swithaddr=0;
    111.   saddr =acc->ac_souraddr;     daddr  =acc->ac_destaddr;
    112.   sclient=acc->ac_localclient; dclient=acc->ac_remoteclient;
    113.   if (acc->ac_recvport->pt_portnumber) {        // порт 2-LAN карты
    114.     saddr   =daddr;  daddr  =acc->ac_souraddr;
    115.     dclient=sclient; sclient=acc->ac_remoteclient;
    116.     swithaddr=1; }
    117.  
    118.   if (sclient) {
    119.     if (dclient==0) { // поиск по клиенту источнику
    120.       do {
    121.     if (us->ab_status==0) goto setnew;        // чистая
    122.     if (us->ab_client==sclient) {
    123.       if (us->ab_linkclient)        goto checkmindc;
    124.       if (us->ab_destipaddr!=daddr) goto checkmindc;
    125.       us->ab_souripaddr=saddr;  // если изменится адрес
    126.       goto settime; }    // найден
    127.     if (us->ab_linkclient==sclient) {
    128.       if (us->ab_client)            goto checkmindc;
    129.       if (us->ab_souripaddr!=daddr) goto checkmindc;
    130.       us->ab_destipaddr=saddr;
    131.       swithaddr^=1; goto settime; }    // найден
    132.     checkmindc:
    133.     if (us->ab_status&ABS_CLOSED) {
    134.       if (us->ab_closetime<minclose) { usclosed=us; minclose=us->ab_closetime; }
    135.       continue; }
    136.     if (us->ab_lasttime<minlast) { uslast=us; minlast=us->ab_lasttime; }
    137.       } while((++us)<&usershow[MAXABONENT]);
    138.       goto getlast; }
    139.     // поиск для пары клиентов
    140.     do {
    141.       if (us->ab_status==0) goto setnew;        // чистая
    142.       if ((us->ab_client==sclient)&&(us->ab_linkclient==dclient)) {
    143.     us->ab_souripaddr=saddr; us->ab_destipaddr=daddr; // если изменится адрес
    144.     goto settime; }
    145.       if ((us->ab_client==dclient)&&(us->ab_linkclient==sclient)) {
    146.     us->ab_souripaddr=daddr; us->ab_destipaddr=saddr; // если изменится адрес
    147.     swithaddr^=1; goto settime; }
    148.       if (us->ab_status&ABS_CLOSED) {
    149.     if (us->ab_closetime<minclose) { usclosed=us; minclose=us->ab_closetime; }
    150.     continue; }
    151.       if (us->ab_lasttime<minlast) { uslast=us; minlast=us->ab_lasttime; }
    152.     } while((++us)<&usershow[MAXABONENT]);
    153.     goto getlast; }
    154.  
    155.   if (dclient) { // sclient==0 - поиск по клиенту получателю
    156.     do {
    157.       if (us->ab_status==0) goto setnew;        // чистая
    158.       if (us->ab_linkclient==dclient) {
    159.     if (us->ab_client)            goto checkminsc;
    160.     if (us->ab_souripaddr!=saddr) goto checkminsc;
    161.     us->ab_destipaddr=daddr; // если изменится адрес
    162.     goto settime; }
    163.       if (us->ab_client==dclient) {
    164.     if (us->ab_linkclient)           goto checkminsc;
    165.     if (us->ab_destipaddr!=saddr) goto checkminsc;
    166.     us->ab_souripaddr=daddr;  // если изменится адрес
    167.     swithaddr^=1; goto settime; }
    168.       checkminsc:
    169.       if (us->ab_status&ABS_CLOSED) {
    170.     if (us->ab_closetime<minclose) { usclosed=us; minclose=us->ab_closetime; }
    171.     continue; }
    172.       if (us->ab_lasttime<minlast) { uslast=us; minlast=us->ab_lasttime; }
    173.     } while((++us)<&usershow[MAXABONENT]);
    174.     goto getlast; }
    175.  
    176.   do {
    177.     if (us->ab_status==0) goto setnew;        // чистая
    178.     if (((DWRD)us->ab_linkclient|(DWRD)us->ab_client)==0) {
    179.       if ((us->ab_souripaddr==saddr)&&(us->ab_destipaddr==daddr)) goto settime;
    180.       if ((us->ab_souripaddr==daddr)&&(us->ab_destipaddr==saddr)) {
    181.     swithaddr^=1; goto settime; }}
    182.     if (us->ab_status&ABS_CLOSED) {
    183.       if (us->ab_closetime<minclose) { usclosed=us; minclose=us->ab_closetime; }
    184.       continue; }
    185.     if (us->ab_lasttime<minlast) { uslast=us; minlast=us->ab_lasttime; }
    186.   } while((++us)<&usershow[MAXABONENT]);
    187.   getlast:
    188.   // не найдена - выбираю подходящую
    189.   us=uslast; if (usclosed) us=usclosed;
    190.   CloseUserStat(us);
    191.   setnew:
    192.   _MemClearMacro(us,sizeof(usershowtype));
    193.   us->ab_souripaddr=saddr;        // IP адрес по стороне ab_port
    194.   us->ab_destipaddr=daddr;        // IP адрес по стороне ab_port
    195.   us->ab_client    =sclient;
    196.   us->ab_linkclient=dclient;
    197.   settime:
    198.   if (swithaddr) {
    199.     us->ab_port     =0;
    200.     if (acc->ac_linkport) us->ab_port=acc->ac_linkport->pt_portnumber+1;
    201.     us->ab_linkport =acc->ac_recvport->pt_portnumber+1;
    202.     us->ab_guard    =acc->ac_destguard;
    203.     us->ab_linkguard=acc->ac_localguard; }
    204.   else {
    205.     us->ab_linkport =0;
    206.     if (acc->ac_linkport) us->ab_linkport=acc->ac_linkport->pt_portnumber+1;
    207.     us->ab_port     =acc->ac_recvport->pt_portnumber+1;
    208.     us->ab_linkguard=acc->ac_destguard;
    209.     us->ab_guard    =acc->ac_localguard; }
    210.   us->ab_lasttime  =curftime;        // время прошлого обмена (ftime)
    211.   us->ab_closetime =curtick+TIMELIVEABONENT;
    212.   us->ab_status   &=~ABS_CLOSED;
    213.   us->ab_status   |=ABS_DECLARED;
    214.   return us;
    215. }
    Кстати, какими функциями в программе можно замерить производительность?
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    XJess
    Надо писать что оптимизируем. Насколько понял по скорости.
    Второе надо указывать объем обробатываемых данных.

    Для быстрого поиска можно использовать бинарный. А структуру представления зависит от многих факторов.
    Как часто пользователи добавляются в систему и удоляются из нее.
    Можно представить массивом или в виде дерева. Если в виде дерева то AVL (сбаланосированные деревья).

    Для этого есть профайлы или как-то так.
    А если дедовским методом то через функцию получения времени.
    Я бы функцию назвал только не знаю какая у вас система?
     
  3. XJess

    XJess New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2009
    Сообщения:
    4
    Система - Windows, оптимизация - да, по времени, но можно и не только, если есть что улучшить в плане чего-то другого.
     
  4. XJess

    XJess New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2009
    Сообщения:
    4
    А что скажете о хэш-таблице как средстве для поиска в данном случае?
    Насчет объема обрабатываемых данных - а что от этого будет зависеть?

    Кстати, насколько часто добавляются/удаляются данные, не знаю - не сказано.
     
  5. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    XJess
    в любом случае нужно постараться снизить кол-во переборов. определись с условием равенства/неравенства данных, и ты увидишь решение.
    короче, в каком случае у тебя элементы считаются равными, а в каком - нет?
    а со структурой данных для поиска далее определишься, это несложно.
     
  6. gazlan

    gazlan Member

    Публикаций:
    0
    Регистрация:
    22 май 2005
    Сообщения:
    414
    IMHO, лучший вариант для таблицы (usershow) фиксированного размера. Только подобрать хорошую хэширующую функцию.