Способы ускорить постановку огромного дела?C ++ - PullRequest
1 голос
/ 21 июня 2011

Я запускаю файл и имею дело с 30 или около того различными типами фрагментов. Поэтому каждый раз я читаю фрагмент и сравниваю его тип (в шестнадцатеричном формате) с типами фрагментов, которые я знаю. Это быстро или есть другой способ сделать это быстрее?

Вот пример кода, который я использую:

// Iterate through the fragments and address them individually
    for(int i = 0; i < header.fragmentCount; i++) 
    {
        // Read in memory for the current fragment
        memcpy(&frag, (wld + file_pos), sizeof(struct_wld_basic_frag));

        // Deal with each frag type
        switch(frag.id) 
        {
        // Texture Bitmap Name(s)
        case 0x03:
            errorLog.OutputSuccess("[%i] 0x03 - Texture Bitmap Name", i);
            break;
        // Texture Bitmap Info
        case 0x04:
            errorLog.OutputSuccess("[%i] 0x04 - Texture Bitmap Info", i);
            break;
        // Texture Bitmap Reference Info
        case 0x05:
            errorLog.OutputSuccess("[%i] 0x05 - Texture Bitmap Reference Info", i);
            break;
        // Two-dimensional Object
        case 0x06:
            errorLog.OutputSuccess("[%i] 0x06 - Two-dimensioanl object", i);
            break;

Он проходит около 30 из них, и когда есть тысячи фрагментов, он может немного пыхтеть. Как можно посоветовать ускорить этот процесс?

Спасибо!

Ответы [ 8 ]

4 голосов
/ 21 июня 2011

Если все эти случаи одинаковы, за исключением строки формата, рассмотрите наличие массива строк формата и ни одного регистра, как в:

const char *fmtStrings[] = {
  NULL, NULL, NULL,
  "[%i] 0x03 - Texture Bitmap Name",
  "[%i] 0x04 - Texture Bitmap Info",
  /* ... */
};

// ...
errorLog.OutputSuccess(fmtStrings[i], i);
// (range checks elided)

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

2 голосов
/ 21 июня 2011

Оператор case должен быть очень быстрым, потому что когда ваш код оптимизирован (и даже иногда, когда это не так), он реализуется в виде таблицы переходов. Зайдите в отладчик и установите точку останова на коммутаторе и проверьте разборку, чтобы убедиться, что это так.

1 голос
/ 21 июня 2011

Я скептически отношусь к тому, что проблема в 30 случаях. Это не очень большой код по сравнению с тем, что делают ваши методы memcpy и errorLog. Сначала убедитесь, что ваша скорость ограничена временем процессора, а не доступом к диску. Если вы действительно связаны с процессором, изучите код в профилировщике.

1 голос
/ 21 июня 2011

Я думаю, что выполнение memcpy, вероятно, вызывает много накладных расходов. Возможно, используйте ваш оператор switch для прямого доступа к вашим данным в (wld + file_pos).

1 голос
/ 21 июня 2011

Если ваши идентификаторы фрагментов не слишком редки, вы можете создать массив имен типов фрагментов и использовать его в качестве таблицы поиска.

static const char *FRAGMENT_NAMES[] = {
    0,
    0,
    0,
    "Texture Bitmap Name", // 0x03
    "Texture Bitmap Info", // 0x04
    // etc.
};

...

const char *name = FRAGMENT_NAMES[frag.id];

if (name) {
    errorLog.OutputSuccess("[%i] %x - %s", i, frag.id, name);
} else {
    // unknown name
}
0 голосов
/ 21 июня 2011

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

struct_wld_basic_frag *frag = (struct_wld_basic_frag *)wld;

for (i=0; i<header.fragmentCount; i++)
    errorlog.OutputSuccess(fragment_strings[frag[i].id], i);

На данный момент я предположил массив строк для разных типов фрагментов, как рекомендовано @Chris и @Ates. Даже в худшем случае это улучшит удобочитаемость и удобство обслуживания без ущерба для скорости. В лучшем случае это может (например) улучшить использование кэша и значительно повысить скорость - одна копия кода для вызова errorlog.outputSuccess вместо 30 отдельных копий может освободить место для множества других «вещей» в кэше ,

Если вы не копируете данные каждый раз, гораздо больше шансов на успех. В то же время, я, вероятно, должен добавить, что возможно , чтобы это могло вызвать проблему - если данные неправильно выровнены в исходном буфере, попытка использовать указатель не будет работать.

0 голосов
/ 21 июня 2011

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

  const char* typeNames[] = {"Texture Bitmap Name", "Texture Bitmap Info", ...};

  /* for each frag.id: */
  if (LOWER_LIMIT <= frag.id && frag.id < UPPER_LIMIT) {
    printf("[%i] %#02x - %s\n", i, frag.id, typeNames[frag.id-LOWER_LIMIT]);
  } else {
   /* complain about error */
  }
0 голосов
/ 21 июня 2011

Если ваши операторы журнала всегда являются строками вида "[% i] 0xdd - message ...", а frag.id всегда является целым числом от 0 до 30, вы можете вместо этого объявить массив строк:

std::string messagesArray[] = {"[%i] 0x00 - message one", "[%i] 0x01 - message two", ...}

Затем замените оператор switch на

errorLog.OutputSuccess(messagesArray[frag.id], i);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...