Executable работает быстрее на Wine, чем Windows - почему?
Решение: Очевидно, виновником было использование floor()
, производительность которого оказалась зависимой от ОС в glibc.
Это следующий вопрос к предыдущему: Такая же программа быстрее в Linux, чем Windows, - почему?
У меня есть небольшая программа на С++, которая при компиляции с nuwen gcc 4.6.1 работает быстрее на Wine, чем Windows XP (на том же компьютере). Вопрос: почему это происходит?
Тайм-ауты составляют ~ 15,8 и 25,9 секунды, для Wine и Windows соответственно. Обратите внимание, что я говорю об одном и том же исполняемом файле, а не только о той же программе на С++.
Исходный код находится в конце сообщения. Скомпилированный исполняемый файл здесь (если вы доверяете мне достаточно).
Эта конкретная программа не делает ничего полезного, это всего лишь минимальный пример, сложенный с большей программы, которую я имею. См. этот другой вопрос для более точного бенчмаркинга исходной программы (важно!!), и наиболее распространенные возможности исключены (например, другие программы, запугивающие CPU на Windows, штраф запуска процесса, разницу в системных вызовах, таких как распределение памяти). Также обратите внимание, что в то время как здесь я использовал rand()
для простоты, в оригинале я использовал свой собственный RNG, который, как я знаю, не выделяет кучу.
Причина, по которой я открыла новый вопрос по этой теме, заключается в том, что теперь я могу опубликовать фактический упрощенный пример кода для воспроизведения этого явления.
Код:
#include <cstdlib>
#include <cmath>
int irand(int top) {
return int(std::floor((std::rand() / (RAND_MAX + 1.0)) * top));
}
template<typename T>
class Vector {
T *vec;
const int sz;
public:
Vector(int n) : sz(n) {
vec = new T[sz];
}
~Vector() {
delete [] vec;
}
int size() const { return sz; }
const T & operator [] (int i) const { return vec[i]; }
T & operator [] (int i) { return vec[i]; }
};
int main() {
const int tmax = 20000; // increase this to make it run longer
const int m = 10000;
Vector<int> vec(150);
for (int i=0; i < vec.size(); ++i)
vec[i] = 0;
// main loop
for (int t=0; t < tmax; ++t)
for (int j=0; j < m; ++j) {
int s = irand(100) + 1;
vec[s] += 1;
}
return 0;
}
UPDATE
Кажется, что если я заменил irand()
на что-то детерминированное, например
int irand(int top) {
static int c = 0;
return (c++) % top;
}
тогда разница во времени исчезает. Я хотел бы отметить, что в моей оригинальной программе я использовал другой RNG, а не систему rand()
. Я сейчас врываюсь в источник этого.
ОБНОВЛЕНИЕ 2
Теперь я заменил функцию irand()
эквивалентом того, что у меня было в исходной программе. Он немного длинный (алгоритм от Numerical Recipes), но дело в том, чтобы показать, что никакие системные библиотеки не называются эксплицитно (кроме возможно, через floor()
). Однако разница во времени все еще существует!
Возможно, может быть виноват floor()
? Или компилятор генерирует вызовы на что-то еще?
class ran1 {
static const int table_len = 32;
static const int int_max = (1u << 31) - 1;
int idum;
int next;
int *shuffle_table;
void propagate() {
const int int_quo = 1277731;
int k = idum/int_quo;
idum = 16807*(idum - k*int_quo) - 2836*k;
if (idum < 0)
idum += int_max;
}
public:
ran1() {
shuffle_table = new int[table_len];
seedrand(54321);
}
~ran1() {
delete [] shuffle_table;
}
void seedrand(int seed) {
idum = seed;
for (int i = table_len-1; i >= 0; i--) {
propagate();
shuffle_table[i] = idum;
}
next = idum;
}
double frand() {
int i = next/(1 + (int_max-1)/table_len);
next = shuffle_table[i];
propagate();
shuffle_table[i] = idum;
return next/(int_max + 1.0);
}
} rng;
int irand(int top) {
return int(std::floor(rng.frand() * top));
}
Ответы
Ответ 1
edit: выяснилось, что виновник был floor()
, а не rand()
, как я подозревал, - см.
обновление в верхней части вопроса OP.
Время выполнения вашей программы во власти вызовов rand()
.
Поэтому я считаю, что rand()
является виновником. Я подозреваю, что базовая функция обеспечивается средой выполнения WINE/Windows, а две реализации имеют разные характеристики производительности.
Самый простой способ проверить эту гипотезу - просто называть rand()
в цикле и время того же исполняемого файла в обеих средах.
edit Я посмотрел исходный код WINE, и вот его реализация rand()
:
/*********************************************************************
* rand ([email protected])
*/
int CDECL MSVCRT_rand(void)
{
thread_data_t *data = msvcrt_get_thread_data();
/* this is the algorithm used by MSVC, according to
* http://en.wikipedia.org/wiki/List_of_pseudorandom_number_generators */
data->random_seed = data->random_seed * 214013 + 2531011;
return (data->random_seed >> 16) & MSVCRT_RAND_MAX;
}
У меня нет доступа к исходному коду Microsoft для сравнения, но меня это не удивило бы, если бы разница в производительности заключалась в получении потока-локального данных, а не в самой RNG.
Ответ 2
Википедия говорит:
Wine - это уровень совместимости, а не эмулятор. Он дублирует функции компьютера Windows, предоставляя альтернативные варианты реализации DLL, которые Windows-программы вызывают, [править] и процесс замените ядро Windows NT. Этот метод дублирования отличается от других методов, которые также могут считаться эмуляцией, где программы Windows запускаются на виртуальной машине. [2] Вино в основном, с использованием обратного проектирования с использованием черного ящика, для избегайте проблем с авторским правом.
Это означает, что разработчики вина могут заменить вызов api на что-нибудь вообще, до тех пор, пока конечный результат будет таким же, как вы бы получили с собственным вызовом Windows. И я полагаю, что они не были ограничены необходимостью сделать его совместимым с остальной частью Windows.
Ответ 3
Из того, что я могу сказать, используемые стандартные библиотеки C будут разными в двух разных сценариях. Это влияет на вызов rand(), а также на floor().
С сайта mingw... MinGW compilers provide access to the functionality of the Microsoft C runtime and some language-specific runtimes.
Запуск под XP, это будет использовать библиотеки Microsoft. Это просто.
Однако модель под вином гораздо сложнее. Согласно этой диаграмме, вступает в действие операционная система libc. Это может быть разница между ними.
Ответ 4
В то время как Wine - это в основном Windows, вы по-прежнему сравниваете яблоки с апельсинами. Кроме того, это не только яблоки/апельсины, базовые транспортные средства, перевозящие эти яблоки и апельсины, совершенно разные.
Короче говоря, ваш вопрос может быть тривиально перефразирован как "этот код работает быстрее на Mac OSX, чем на Windows" и получает тот же ответ.