如何在大多数QML应用程序中追踪seg故障?
具体错误是:*** Error in 'app/app': double free or corruption (!prev): 0x00007ff4bce5e710 ***
只有当我有ComputeCommand
时才会发生这种情况(如下所示)。错误本身就是间歇性的。这是在使用clang构建的Ubuntu 14.04.03上使用Qt 5.7.1(在Qt 5.8.0和Ubuntu 16.04中相同)。在调试模式下(使用gdb)我没有得到任何有用的东西(见下文),只是在我的应用程序中发生了一些事情,然后是一堆没有符号信息的Qt3DRender库。 Valgrind和Hellgrind使用它的速度太慢而无法使用它(这个应用程序可视化数百个点,而且我无法在真正的低点数时引发问题),ASAN和TSAN会报告问题,但没有符号/行数字我无法跟踪任何事情。
我的设置为main.qml
- > Scene3d
- > RenderSettings
,Entity
我使用自己编写的自定义缓冲区和几何体(PointBuffer
,PointGeometry
)我写了但没有包含。它们分别从QBuffer
和QGeomotry
继承。
基本上,当激活计算着色器时(实体上的ComputeCommand
组件和DispatchCompute
上的viewport
),我会得到上面的间歇性seg故障。我添加的唯一异步组件是我的缓冲区由我自己的线程写入,我用std::mutex
包围了这个,但我不认为这是问题所在我在QBuffer
或QGeometry
代码中看不到任何互斥锁。
着色器本身会创建一个连贯的缓冲区(layout (std430, binding = 0) coherent buffer Particles
),否则只需读入并打印出这些点;当我没有任何操作时工作......当然直到seg故障。
我的问题是,我是否配置了计算着色器?或者有更好的方法来调试它吗?
我能追踪的最多问题是它只发生在几何体上缓冲区刷新之后。
RenderSettings :
RenderSettings {
property CameraSet cameraSet
property real userViewWidth: 0.79
property real topOrthoViewHeight: 0.79
activeFrameGraph: Viewport {
id: viewport
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
RenderSurfaceSelector {
ClearBuffers {
buffers: ClearBuffers.ColorDepthBuffer
NoDraw {}
}
// Compute Pass
DispatchCompute {
workGroupX: 1024; workGroupY: 1; workGroupZ: 1
TechniqueFilter {
matchAll: [
FilterKey { name: "type"; value: "compute" }
]
}
}
Viewport {
id: userViewport
normalizedRect: Qt.rect(0, 0, 0.5, 1.0)
CameraSelector {
id: userCameraSelectorViewport
camera: cameraSet.user.camera
}
}
// Second and third viewport...
}
}
}
材料(PointMaterial
)
Material {
property PointBuffer dataBuffer;
ShaderProgram {
id: computeShader
computeShaderCode: loadSource("qrc:/shaders/pointcloud.comp")
}
ShaderProgram {
id: drawShader
vertexShaderCode: loadSource("qrc:/shaders/pointcloud.vert")
fragmentShaderCode: loadSource("qrc:/shaders/pointcloud.frag")
}
effect: Effect {
techniques: [
Technique {
renderPasses: [
RenderPass {
shaderProgram: computeShader
parameters: [
// Point buffer
Parameter { name: "Particles"; value: dataBuffer }
]
}
] // renderpasses
filterKeys: [
FilterKey { name: "type"; value: "compute" }
]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 4
minorVersion: 3
}
},
Technique {
renderPasses: [
RenderPass {
shaderProgram: drawShader
renderStates: [
PointSize { sizeMode: PointSize.Programmable }
]
parameters: [
Parameter { name: "pointSize"; value: 0.4 }
]
}
] // renderPasses
filterKeys: [
FilterKey { name: "type"; value: "draw" }
]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 4
minorVersion: 3
}
} // technique
] // techniques
}
}
实体:
Entity {
property PointBuffer buffer: PointBuffer {
id: pointBuffer
type: Buffer.VertexBuffer
}
PointsMaterial {
id: pointsMaterial
dataBuffer: pointBuffer
}
Entity {
property GeometryRenderer pointRenderer: GeometryRenderer {
instanceCount: 1 // How many times to run this geometry, since we write
// all points in the buffer once, only call this once.
primitiveType: GeometryRenderer.Points
geometry: PointGeometry { buffer: pointBuffer }
}
// https://doc-snapshots.qt.io/qt5-5.7/qml-computecommand.html
property ComputeCommand computeCommand: ComputeCommand {
workGroupX: 1024; workGroupY: 1; workGroupZ: 1
}
components: [ pointRenderer, computeCommand, pointsMaterial ]
}
}
我试图限制我发布的代码量以保持问题的小,但我很乐意添加任何其他内容,如果它有助于解决问题。
主线程的My(gdb)调试器输出是:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff9e9cc700 (LWP 8208)]
0x00007ffff33e058c in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
(gdb) bt
#0 0x00007ffff33e058c in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#1 0x00007ffff33e6619 in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#2 0x00007ffff338fe05 in Qt3DRender::Render::Renderer::performCompute(Qt3DRender::Render::RenderView const*, Qt3DRender::Render::RenderCommand*) () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#3 0x00007ffff3392610 in Qt3DRender::Render::Renderer::executeCommandsSubmission(Qt3DRender::Render::RenderView const*) () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#4 0x00007ffff3392b14 in Qt3DRender::Render::Renderer::submitRenderViews(QVector<Qt3DRender::Render::RenderView*> const&) () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#5 0x00007ffff3394bf2 in Qt3DRender::Render::Renderer::doRender() ()
from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt53DRender.so.5
#6 0x00007fffc723a806 in ?? () from /opt/Qt5.7.1/5.7/gcc_64/qml/QtQuick/Scene3D/libqtquickscene3dplugin.so
#7 0x00007ffff1f56e3d in QMetaObject::activate(QObject*, int, int, void**) ()
from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt5Core.so.5
#8 0x00007ffff3ef865e in QQuickWindowPrivate::renderSceneGraph(QSize const&) ()
from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt5Quick.so.5
#9 0x00007ffff3ecabd1 in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt5Quick.so.5
#10 0x00007ffff3ecbe58 in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt5Quick.so.5
#11 0x00007ffff1d68539 in ?? () from /opt/Qt5.7.1/5.7/gcc_64/lib/libQt5Core.so.5
#12 0x00007ffff0eb3184 in start_thread (arg=0x7fff9e9cc700) at pthread_create.c:312
#13 0x00007ffff11c337d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
非常确定我已将此缩小到竞争状态。我已经淘汰了我正在使用的其他库,我认为这可能导致问题,而且没有。基本上,计算过滤器和异步重写的缓冲区的组合会导致此seg错误。我不确定是否有某种方法可以使用互斥锁来保护它。现在我想看看我是否可以用C ++重写我的实体,以便更好地控制计算着色器的执行方式。
答案 0 :(得分:0)
我认为这里的seg错误的原因是我更新缓冲区的结果。在我的PointBuffer
中,我有一个异步任务,它调用Qt3DRender::QBuffer::setData(new_data)
,其中new_data
是QByteArray
。
要设置数据,我在堆栈上创建QByteArray
,将数据复制到其中,然后使用Qt3DRender::QBuffer::setData(my_qbyte_array)
这会将我的堆栈变量暴露给应用程序的其余部分,删除时会导致seg错误。
相反,我改为:
Qt3DRender::QBuffer::setData(
QByteArray::fromRawData(
reinterpret_cast<const char*>(points_.linearize()),
sizeof(PointType) * pointCount
)
)
这反而指向我的原始数据(因此不需要bug拷贝)并且不会绑定到任何临时数据。
我提到的另一个解决方案,我使用的是Qt 5.8.0的新版本
QBuffer::updateData
docs 函数。有了这个,我创建了一个本地QByteArray
,但随后将其复制到我当前的数据中。这有问题(特别是尺寸)并且效率较低,但我想我还是会提到它。