Ограничьте список слов в XML-схеме

Ваш подход к сравнительному анализу в корне неверен, а ваш «осторожный код» фальшивый.

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

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

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

Вы ожидаете [118 ] время, затрачиваемое на каждую итерацию цикла. Это неправильно. Современные процессоры не выполняют команды последовательно, последовательно. Современные процессоры выполняют конвейеризацию, предсказывают переходы, выполняют несколько инструкций параллельно и (достаточно быстрые процессоры) выходят из строя. .

Так что после На первой итерации цикла сравнительного анализа все ветви отлично прогнозируются на следующие почти 100000000 итераций. Это позволяет процессору спекулировать . Фактически, условная ветвь в цикле сравнительного анализа исчезает, как и большая часть стоимости косвенного вызова. Фактически, CPU может развернуть цикл:

movss  xmm0, number
movaps  xmm1, xmm0
rsqrtss xmm1, xmm0
mulss   xmm0, xmm1
movss  xmm0, number
movaps  xmm1, xmm0
rsqrtss xmm1, xmm0
mulss   xmm0, xmm1
movss  xmm0, number
movaps  xmm1, xmm0
rsqrtss xmm1, xmm0
mulss   xmm0, xmm1
...

или, для другого цикла

movss  xmm0, number
sqrtss  xmm0, xmm0
movss  xmm0, number
sqrtss  xmm0, xmm0
movss  xmm0, number
sqrtss  xmm0, xmm0
...

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

Чтобы быть справедливым,

call   rbp
sub    rbx, 0x1
jne    15b0 

все еще выполняются , но единственные ресурсы, которые они берут из кода с плавающей запятой, - это кэш декодирования / микрооперации и порты выполнения. Примечательно, что, хотя код целочисленного цикла имеет цепочку зависимостей (обеспечивающую минимальное время выполнения), код с плавающей запятой не несет в себе зависимости . Кроме того, код с плавающей точкой состоит из множества взаимно полностью независимых коротких цепочек зависимостей.

Если вы ожидаете, что ЦП будет выполнять инструкции последовательно, ЦП может вместо этого выполнять их параллельно.

Небольшой взгляд на https://agner.org/optimize/instruction_tables.pdf показывает, почему это параллельное выполнение не работает для sqrtss на Nehalem:

instruction: SQRTSS/PS
latency: 7-18
reciprocal throughput: 7-18

[1139 ] т.е. инструкция не может быть передана по конвейеру и выполняется только на одном порту выполнения. Напротив, для movaps, rsqrtss, mulss:

instruction: MOVAPS/D
latency: 1
reciprocal throughput: 1

instruction: RSQRTSS
latency: 3
reciprocal throughput: 2

instruction: MULSS
latency: 4
reciprocal throughput: 1

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

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

float x = INITIAL_VALUE;
for (i = 0; i < 100000000; i++)
    x = benchmarked_function(x);

Очевидно, что вы не станете сравнивать один и тот же ] введите таким образом, если только INITIAL_VALUE не является фиксированной точкой benchmarked_function(). Тем не менее, вы можете организовать , чтобы она была фиксированной точкой расширенной функции, вычислив float diff = INITIAL_VALUE - benchmarked_function(INITIAL_VALUE); и затем сделав цикл

float x = INITIAL_VALUE;
for (i = 0; i < 100000000; i++)
    x = diff + benchmarked_function(x);

с относительно небольшими издержками, хотя тогда вы должны убедитесь, что ошибки с плавающей точкой не накапливаются, чтобы существенно изменить значение, переданное в benchmarked_function().

5
задан andypaxo 1 May 2009 в 19:07
поделиться

3 ответа

After triple-checking that XML Schema (XSD) regexes really don't support any of the features that would make this task easy (particularly lookaheads and anchors), I've come up with an approach that seems to work. I used free-spacing mode to make it easier to read, but that's another feature the XSD flavor doesn't support.

  [^ibs].* |
  i(.{0,1} | [^n].* | n[^t].* | nt.+) |
  b(.{0,2} | [^y].* | y[^t].* | yt[^e].* | yte.+) |
  s(.{0,4} | [^t].* | t[^r].* | tr[^i].* | tri[^n].* | trin[^g].* | tring.+)

The first alternative matches anything that doesn't start with the initial letter of any of the keywords. Each of the other top-level alternatives matches a string that starts with the same letter as one of the keywords but:

  • is shorter than the keyword,
  • has a different second letter, different third letter, etc., or
  • is longer than the keyword.

Note that XSD regexes don't support explicit anchors (i.e., ^, $, \A, \z), but all matches are implicitly anchored at both ends.

One potential problem I can see: if the list of keywords is long, you might run up against a limit on the sheer length of the regex.

6
ответ дан 14 December 2019 в 08:59
поделиться

Без негативного взгляда это довольно утомительно. Прикреплено регулярное выражение, которое работает с некоторыми модульными тестами. Это написано на Perl, а не на XSD, но это довольно простое регулярное выражение, поэтому оно должно работать ... Вы должны удалить пробел из регулярного выражения перед его использованием. Я добавил пробел только для того, чтобы его было немного легче читать.

Примечание: я не знаю, разрешены ли "\ A" и "\ z" в XSD. Если нет, замените на «^» и «$» соответственно.

use Test::More 'no_plan';

my $re = qr/\A(\z|[^ibs]                                                        
   |i(\z|[^n]|n(\z|[^t]|t.))                                                    
   |b(\z|[^y]|y(\z|[^t]|t(\z|[^e]|e.)))                                         
   |s(\z|[^t]|t(\z|[^r]|r(\z|[^i]|i(\z|[^n]|n(\z|[^g]|g.))))))/x;

for my $str ( qw(inter bytes ins str strings in sdgsdfger i b s by byt bite st \
str stri strin strink) ) {
   like($str, $re, $str);
}

for my $str ( qw(int byte string) ) {
   unlike($str, $re, $str);
}
0
ответ дан 14 December 2019 в 08:59
поделиться

Должна ли это быть схема W3C (она же «схема XML»)? Или будет работать стандартная альтернатива, такая как RelaxNG ? Возможно, я ошибаюсь, но я подумал, что у него есть несколько препятствий на пути объединения ограничений, в том числе возможность делать пересечения.

1
ответ дан 14 December 2019 в 08:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: