c++ - programas - El ejecutable se ejecuta más rápido en Wine que en Windows, ¿por qué?
wine download (4)
Por lo que puedo decir, las bibliotecas estándar de C utilizadas serán diferentes en los dos escenarios diferentes. Esto afecta a la llamada de rand () así como a floor ().
Desde el sitio mingw ... los MinGW compilers provide access to the functionality of the Microsoft C runtime and some language-specific runtimes.
Ejecutándose bajo XP, esto usará las bibliotecas de Microsoft. Parece sencillo.
Sin embargo, el modelo bajo vino es mucho más complejo. De acuerdo con este diagrama , la libc del sistema operativo entra en juego. Esta podría ser la diferencia entre los dos.
Solución: Al parecer, el culpable fue el uso de floor()
, cuyo rendimiento resulta ser dependiente del sistema operativo en glibc.
Esta es una pregunta de seguimiento para una anterior: el mismo programa más rápido en Linux que en Windows, ¿por qué?
Tengo un pequeño programa en C ++ que, cuando se compila con nuwen gcc 4.6.1 , se ejecuta mucho más rápido en Wine que en Windows XP (en la misma computadora). La pregunta: ¿por qué sucede esto?
Los tiempos son ~ 15.8 y 25.9 segundos, para Wine y Windows respectivamente. Tenga en cuenta que estoy hablando del mismo ejecutable , no solo del mismo programa C ++.
El código fuente está al final de la publicación. El ejecutable compilado está here (si confías lo suficiente en mí).
Este programa en particular no hace nada útil, es solo un ejemplo mínimo derivado de un programa más grande que tengo. Consulte esta otra pregunta para obtener una evaluación comparativa más precisa del programa original (¡importante!) Y las posibilidades más comunes descartadas (como otros programas que acaparan la CPU en Windows, penalización de inicio del proceso, diferencia en las llamadas del sistema, como la asignación de memoria) . También tenga en cuenta que aunque aquí utilicé rand()
por simplicidad, en el original usé mi propio RNG, que sé que no tiene asignación de pila.
La razón por la que abrí una nueva pregunta sobre el tema es que ahora puedo publicar un ejemplo de código simplificado para reproducir el fenómeno.
El código:
#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;
}
ACTUALIZAR
Parece que si sustituyo irand()
arriba por algo determinista como
int irand(int top) {
static int c = 0;
return (c++) % top;
}
entonces la diferencia de tiempo desaparece. Sin embargo, me gustaría señalar que en mi programa original usé un RNG diferente, no el sistema rand()
. Estoy cavando en la fuente de eso ahora.
ACTUALIZACIÓN 2
Ahora reemplacé la función irand()
con un equivalente de lo que tenía en el programa original. Es un poco largo (el algoritmo es de Recetas Numéricas ), pero el punto era mostrar que no se está llamando explícitamente a las bibliotecas del sistema (excepto posiblemente a través de floor()
). Sin embargo, la diferencia de tiempo sigue ahí!
Tal vez el floor()
podría ser el culpable? ¿O el compilador genera llamadas a otra cosa?
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));
}
Si bien Wine es básicamente Windows, todavía estás comparando manzanas con naranjas. Además, no solo se trata de manzanas / naranjas, sino que los vehículos subyacentes que transportan esas manzanas y naranjas son completamente diferentes.
En resumen, su pregunta podría reformularse de manera trivial, ya que "este código se ejecuta más rápido en Mac OSX que en Windows" y obtiene la misma respuesta.
Wikipedia dice:
El vino es una capa de compatibilidad, no un emulador. Duplica las funciones de una computadora con Windows al proporcionar implementaciones alternativas de las DLL a las que llaman los programas de Windows, [citación necesaria] y un proceso para sustituir el kernel de Windows NT. Este método de duplicación difiere de otros métodos que también podrían considerarse emulación, donde los programas de Windows se ejecutan en una máquina virtual. [2] El vino se escribe predominantemente utilizando pruebas de caja negra de ingeniería inversa, para evitar problemas de copyright.
Esto implica que los desarrolladores de wine podrían reemplazar una llamada de API con cualquier cosa, siempre y cuando el resultado final sea el mismo que obtendría con una llamada de Windows nativa. Y supongo que no estaban limitados por la necesidad de hacerlo compatible con el resto de Windows.
edición: Resultó que el culpable era floor()
y no rand()
como sospechaba, vea la actualización en la parte superior de la pregunta del OP.
El tiempo de ejecución de su programa está dominado por las llamadas a rand()
.
Por lo tanto creo que rand()
es el culpable. Sospecho que la función subyacente la proporciona WINE / Windows runtime, y las dos implementaciones tienen características de rendimiento diferentes.
La forma más fácil de probar esta hipótesis sería simplemente llamar a rand()
en un bucle y cronometrar el mismo ejecutable en ambos entornos.
edit He echado un vistazo al código fuente de WINE, y aquí está su implementación de rand()
:
/*********************************************************************
* rand (MSVCRT.@)
*/
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;
}
No tengo acceso al código fuente de Microsoft para comparar, pero no me sorprendería si la diferencia en el rendimiento estuviera en la obtención de datos de subprocesos locales en lugar de en el propio RNG.