X cuelga debido a la aplicación (use C++, Qt, OpenGL)

6 minutos de lectura

avatar de usuario
poljak181

Mi aplicación obtiene datos de la red y los dibuja en la escena (la escena usa un motor OpenGL hecho a mano).

Funciona durante varias horas. Cuando no estoy usando mi escritorio, mi monitor, debido a Display Power Manager Signaling (dpms), se apaga. Y luego, cuando toco el mouse o el teclado, el monitor se enciende y la aplicación cuelga (X cuelga también).

Si lo hago
xset -dmps
el sistema operativo no utiliza dpms y la aplicación funciona estable.

Estos problemas ocurren en Centos 6 y Archlinux, pero cuando ejecuto la aplicación en Ubuntu 12.10, ¡funciona muy bien!

Probé diferentes controladores de NVidia. Sin efecto.

Intenté usar ssh para iniciar sesión de forma remota y adjuntarlo al proceso con gdb. Después de encender el monitor, no puedo encontrar la aplicación en la tabla de procesos.

¿Cómo diagnosticar el problema? ¿Qué sucede (en el entorno OpengGL) cuando el monitor se apaga o se enciende? ¿Ubuntu hace algo especial cuando usa dpms?

¡Tenemos una conjetura por las razones del problema! Cuando se apaga el monitor perdemos el contexto OpenGL. Cuando el monitor se activa, la aplicación se cuelga (sin contexto). Y la diferencia de comportamiento según el sistema operativo se debe a las diferentes conexiones del monitor: el monitor para Kubuntu está conectado con un cable VGA. Y entonces (probablemente) no tiene influencia en el comportamiento de X.

  • Archlinux es un tipo de distribución de lanzamiento continuo, CentOS es una distribución orientada al servidor, si desea un buen soporte multimedia y capacidades OpenGL sin demasiado esfuerzo, probablemente esté en el lado equivocado. Archlinux es un poco como Debian Sid (las pruebas de Debian a veces son incluso peores), además, cada vez que toco esta 2 distribución, tengo más o menos los mismos problemas con los controladores de la GPU, principalmente porque el kernel y X siempre se actualizan a la última versión y la GPU. los conductores se están quedando atrás.

    – usuario2485710

    22 de noviembre de 2013 a las 12:03


  • Si el proceso ya no está en la tabla de procesos, es posible que se haya bloqueado. Si usa ulimit (en bash) o limit (en csh) para permitir que se descargue un archivo de volcado central, es posible que pueda usar ese archivo central para depurar el problema.

    – Henrik Carlqvist

    27 de octubre de 2014 a las 6:47

  • Parece que es un problema del servidor X, creo que otras terminales virtuales aún estarían en condiciones de funcionamiento cuando esto suceda, suba a una y use un monitor de proceso para ver si X está usando el 100% de la CPU. Menciono esto porque me he encontrado con este problema antes. La única forma explicable de por qué sucede esto es debido a un error en X, nunca debería ejecutarse en bucles infinitos debido a una entrada no válida. Lo mejor que puede hacer si ese es el problema es degradar su versión de X. Si ese no es el caso, intente valgrind en su aplicación.

    – Madura Anushanga

    23 de diciembre de 2014 a las 7:56

  • Si estoy seguro de que el servidor X está bloqueado, tomaría 3 volcados de núcleo del proceso del servidor X, con aproximadamente 1 minuto de diferencia, para identificar por qué está bloqueado.

    – Malcolm McCaffery

    19 de julio de 2015 a las 22:52

  • Tal vez sea una cuestión de palabra clave o agarre del mouse, y podría estar relacionado con el administrador de ventanas.

    – Basile Starynkevitch

    27 de julio de 2015 a las 19:27

avatar de usuario
doug65536

¿Ha intentado agregar soporte de robustez a su implementación de OpenGL usando GL_ARB_robustez?

2.6 “Recuperación de restablecimiento de gráficos”

Ciertos eventos pueden resultar en un reinicio del contexto GL. Dicho restablecimiento hace que se pierda todo el estado del contexto. La recuperación de tales eventos requiere la recreación de todos los objetos en el contexto afectado. El estado actual del estado de reinicio de gráficos es devuelto por

enum GetGraphicsResetStatusARB();

La constante simbólica devuelta indica si el contexto GL ha estado en un estado de reinicio en algún momento desde la última llamada a GetGraphicsResetStatusARB. NO_ERROR indica que el contexto GL no ha estado en un estado de reinicio desde la última llamada. GUILTY_CONTEXT_RESET_ARB indica que se ha detectado un reinicio atribuible al contexto actual de GL. INNOCENT_CONTEXT_RESET_ARB indica que se ha detectado un restablecimiento que no es atribuible al contexto actual del libro mayor. UNKNOWN_CONTEXT_RESET_ARB indica un restablecimiento de gráficos detectado cuya causa se desconoce.

Además, asegúrese de tener un contexto de depuración cuando inicialice su contexto y use el ARB_debug_salida extensión para recibir la salida del registro.

void DebugMessageControlARB(enum source,
                            enum type,
                            enum severity,
                            sizei count,
                            const uint* ids,
                            boolean enabled);

void DebugMessageInsertARB(enum source,
                           enum type,
                           uint id,
                           enum severity,
                           sizei length, 
                           const char* buf);

void DebugMessageCallbackARB(DEBUGPROCARB callback,
                             const void* userParam);

uint GetDebugMessageLogARB(uint count,
                           sizei bufSize,
                           enum* sources,
                           enum* types,
                           uint* ids,
                           enum* severities,
                           sizei* lengths, 
                           char* messageLog);

void GetPointerv(enum pname,
                 void** params);

Por ejemplo:

// Initialize GL_ARB_debug_output ASAP
if (glfwExtensionSupported("GL_ARB_debug_output"))
{
    typedef void APIENTRY (*glDebugMessageCallbackARBFunc)
            (GLDEBUGPROCARB callback, const void* userParam);
    typedef void APIENTRY (*glDebugMessageControlARBFunc)
            (GLenum source, GLenum type, GLenum severity,
             GLsizei count, const GLuint* ids, GLboolean enabled);
    auto glDebugMessageCallbackARB = (glDebugMessageCallbackARBFunc)
            glfwGetProcAddress("glDebugMessageCallbackARB");
    auto glDebugMessageControlARB = (glDebugMessageControlARBFunc)
            glfwGetProcAddress("glDebugMessageControlARB");
    glDebugMessageCallbackARB(debugCallback, this);
    glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE,
            GL_DEBUG_SEVERITY_LOW_ARB, 0, nullptr, GL_TRUE);
}

std::string GlfwThread::severityString(GLenum severity)
{
    switch (severity)
    {
    case GL_DEBUG_SEVERITY_LOW_ARB: return "LOW";
    case GL_DEBUG_SEVERITY_MEDIUM_ARB: return "MEDIUM";
    case GL_DEBUG_SEVERITY_HIGH_ARB: return "HIGH";
    default: return "??";
    }
}

std::string GlfwThread::sourceString(GLenum source)
{
    switch (source)
    {
    case GL_DEBUG_SOURCE_API_ARB: return "API";
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "SYSTEM";
    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "SHADER_COMPILER";
    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "THIRD_PARTY";
    case GL_DEBUG_SOURCE_APPLICATION_ARB: return "APPLICATION";
    case GL_DEBUG_SOURCE_OTHER_ARB: return "OTHER";
    default: return "???";
    }
}

std::string GlfwThread::typeString(GLenum type)
{
    switch (type)
    {
    case GL_DEBUG_TYPE_ERROR_ARB: return "ERROR";
    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return "DEPRECATED_BEHAVIOR";
    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "UNDEFINED_BEHAVIOR";
    case GL_DEBUG_TYPE_PORTABILITY_ARB: return "PORTABILITY";
    case GL_DEBUG_TYPE_PERFORMANCE_ARB: return "PERFORMANCE";
    case GL_DEBUG_TYPE_OTHER_ARB: return "OTHER";
    default: return "???";
    }
}

// Note: this is static, it is called from OpenGL
void GlfwThread::debugCallback(GLenum source, GLenum type,
                               GLuint id, GLenum severity,
                               GLsizei, const GLchar *message,
                               const GLvoid *)
{
    std::cout << "source=" << sourceString(source) <<
                 " type=" << typeString(type) <<
                 " id=" << id <<
                 " severity=" << severityString(severity) <<
                 " message=" << message <<
                 std::endl;
    AssertBreak(type != GL_DEBUG_TYPE_ERROR_ARB);
}

Es casi seguro que tiene ambas extensiones disponibles en una implementación OpenGL decente. Ellos ayudan, mucho. Los contextos de depuración validan todo y se quejan en el registro. Incluso dan sugerencias de rendimiento en la salida del registro en algunas implementaciones de OpenGL. El uso de ARB_debug_output hace que la verificación glGetError obsoleto: comprueba cada llamada por usted.

Puede comenzar mirando los registros de X, generalmente ubicados en /var/log/ y ~/.xsession-errors. No está descartado que OpenGL esté haciendo algo extraño, por lo que si su aplicación tiene algún registro, actívelo. Habilite los volcados del núcleo ejecutando ulimit -c unlimited. Puede analizar el volcado abriéndolo en gdb de esta manera:

gdb <executable file> <core dump file>

Vea si eso produce algo útil, luego investigue lo que sea.

¿Ha sido útil esta solución?