benchs: revamp benchs for Assimp and OpenCascade

This commit is contained in:
Hugues Delorme 2015-03-23 18:31:10 +01:00
parent 83a8b004f1
commit 00c28e1b44
11 changed files with 278 additions and 370 deletions

74
benchs/CMakeLists.txt Normal file
View File

@ -0,0 +1,74 @@
#############################################################################
## GeomIO Library
## Copyright FougSys (2 Mar. 2015)
## contact@fougsys.fr
##
## This software is a reusable library whose purpose is to provide complete
## I/O support for various CAD file formats (eg. STL)
##
## This software is governed by the CeCILL-B license under French law and
## abiding by the rules of distribution of free software. You can use,
## modify and/ or redistribute the software under the terms of the CeCILL-B
## license as circulated by CEA, CNRS and INRIA at the following URL
## "http://www.cecill.info".
#############################################################################
cmake_minimum_required(VERSION 2.6)
project(gmio_benchmark)
#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# Options
option(BENCHMARK_ASSIMP "Build benchmark for Assimp" ON)
option(BENCHMARK_OPENCASCADE "Build benchmark for OpenCascade" ON)
set(ASSIMP_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Directory where the Assimp library resides")
set(OPENCASCADE_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Directory where the OpenCascade library resides")
set(GMIO_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Directory where the GeomIO library resides")
# List source files in commons/
file(GLOB COMMONS_FILES commons/*)
set(COMMONS_FILES ${COMMONS_FILES})
#add_definitions(-DGMIO_HAVE_STDINT_H)
if(BENCHMARK_ASSIMP)
add_executable(bench_assimp bench_assimp/main.cpp ${COMMONS_FILES})
target_include_directories(
bench_assimp
PUBLIC ${ASSIMP_DIR}/include
PUBLIC ${GMIO_DIR}/include)
target_link_libraries(
bench_assimp
${ASSIMP_DIR}/lib64/assimp.lib
${GMIO_DIR}/lib/gmio.lib)
endif()
if(BENCHMARK_OPENCASCADE)
add_executable(bench_occ
bench_occ/main.cpp
${GMIO_DIR}/src/gmio_support/occ_libstl.cpp
${COMMONS_FILES})
add_definitions(-D_OCC64 -DWNT)
target_include_directories(
bench_occ
PUBLIC ${OPENCASCADE_DIR}/inc
PUBLIC ${GMIO_DIR}/include)
target_link_libraries(
bench_occ
${OPENCASCADE_DIR}/win64/vc11/lib/TKernel.lib
${OPENCASCADE_DIR}/win64/vc11/lib/TKMath.lib
${OPENCASCADE_DIR}/win64/vc11/lib/TKSTL.lib
${GMIO_DIR}/lib/gmio.lib)
endif()
# Find bit size of the target architecture
math(EXPR GMIO_TARGET_ARCH_BIT_SIZE "8 * ${CMAKE_SIZEOF_VOID_P}")
# Specific flags for Visual C++
if(MSVC)
# Disable deprecation warnings about "non-secure" CRT functions
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()

View File

@ -1,15 +0,0 @@
include(../../qmake.build/config.pri)
TEMPLATE = app
TARGET = bench_assimp$$TARGET_SUFFIX
INCLUDEPATH += $$ASSIMP_ROOT/include
HEADERS += ../commons/bench_tools.h
SOURCES += \
../commons/bench_tools.c \
main.cpp
LIBS *= -L$$ASSIMP_ROOT/lib -lassimp
QMAKE_RPATHDIR *= $$ASSIMP_ROOT/lib

View File

@ -1,27 +1,176 @@
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#include "../commons/bench_tools.h"
#include <assimp/Importer.hpp>
#include <assimp/ProgressHandler.hpp>
#include <assimp/scene.h>
extern "C" {
#include "../commons/bench_tools.h"
}
#include <gmio_core/error.h>
#include <gmio_stl/stl_io.h>
#include <cstring>
#include <iostream>
static void assimp_Importer(const char* filepath)
static void bench_assimp_Importer(const char* filepath)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filepath, 0);
if (scene == NULL || scene->mNumMeshes <= 0) {
std::cerr << "Failed to read file " << filepath << std::endl;
}
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filepath, 0);
if (scene == NULL || scene->mNumMeshes <= 0) {
std::cerr << "Failed to read file " << filepath << std::endl;
}
}
static void gmio_assimp_allocate_stl_scene(aiScene* pScene)
{
// allocate one mesh
pScene->mNumMeshes = 1;
pScene->mMeshes = new aiMesh*[1];
aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
pMesh->mMaterialIndex = 0;
// allocate a single node
pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
}
static void gmio_assimp_ascii_begin_solid_func(
void* cookie, size_t stream_size, const char* solid_name)
{
aiScene* pScene = (aiScene*)cookie;
gmio_assimp_allocate_stl_scene(pScene);
aiMesh* pMesh = pScene->mMeshes[0];
std::strcpy(pScene->mRootNode->mName.data, solid_name);
pScene->mRootNode->mName.length = std::strlen(solid_name);
// try to guess how many vertices we could have
// assume we'll need 160 bytes for each face
const unsigned facetSize = 200u;
pMesh->mNumFaces = std::max(1u, static_cast<unsigned>(stream_size) / facetSize);
pMesh->mNumVertices = pMesh->mNumFaces * 3;
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
}
static void gmio_assimp_binary_begin_solid(
void* cookie, uint32_t tri_count, const uint8_t* /*header*/)
{
aiScene* pScene = (aiScene*)cookie;
gmio_assimp_allocate_stl_scene(pScene);
aiMesh* pMesh = pScene->mMeshes[0];
pScene->mRootNode->mName.Set("<STL_BINARY>");
pMesh->mNumFaces = tri_count;
pMesh->mNumVertices = pMesh->mNumFaces*3;
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
}
static void gmio_assimp_add_triangle(
void* cookie, uint32_t tri_id, const gmio_stl_triangle_t* triangle)
{
aiScene* pScene = (aiScene*)cookie;
aiMesh* pMesh = pScene->mMeshes[0];
if (pMesh->mNumFaces <= tri_id) {
// need to resize the arrays, our size estimate was wrong
#if 0
unsigned int iNeededSize = (unsigned int)(sz-mBuffer) / pMesh->mNumFaces;
if (iNeededSize <= 160)
iNeededSize >>= 1; // prevent endless looping
unsigned int add = (unsigned int)((mBuffer+fileSize)-sz) / iNeededSize;
#endif
unsigned int add = pMesh->mNumFaces;
add += add >> 3; // add 12.5% as buffer
const unsigned int iNeededSize = (pMesh->mNumFaces + add)*3;
aiVector3D* pv = new aiVector3D[iNeededSize];
memcpy(pv, pMesh->mVertices, pMesh->mNumVertices*sizeof(aiVector3D));
delete[] pMesh->mVertices;
pMesh->mVertices = pv;
pv = new aiVector3D[iNeededSize];
memcpy(pv, pMesh->mNormals, pMesh->mNumVertices*sizeof(aiVector3D));
delete[] pMesh->mNormals;
pMesh->mNormals = pv;
pMesh->mNumVertices = iNeededSize;
pMesh->mNumFaces += add;
}
aiVector3D* vp = &pMesh->mVertices[tri_id * 3];
aiVector3D* vn = &pMesh->mNormals[tri_id];
*vn = *((aiVector3D*)&triangle->normal);
*vp++ = *((aiVector3D*)&triangle->v1);
*vp++ = *((aiVector3D*)&triangle->v2);
*vp++ = *((aiVector3D*)&triangle->v3);
}
static void gmio_assimp_end_solid(void* cookie)
{
aiScene* pScene = (aiScene*)cookie;
aiMesh* pMesh = pScene->mMeshes[0];
// now copy faces
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i) {
aiFace& face = pMesh->mFaces[i];
face.mIndices = new unsigned int[face.mNumIndices = 3];
for (unsigned int o = 0; o < 3;++o,++p) {
face.mIndices[o] = p;
}
}
// create a single default material, using a light gray diffuse color for consistency with
// other geometric types (e.g., PLY).
aiMaterial* pcMat = new aiMaterial;
aiString s;
s.Set(AI_DEFAULT_MATERIAL_NAME);
pcMat->AddProperty(&s, AI_MATKEY_NAME);
aiColor4D clrDiffuse(0.6f,0.6f,0.6f,1.0f);
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f);
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
pScene->mNumMaterials = 1;
pScene->mMaterials = new aiMaterial*[1];
pScene->mMaterials[0] = pcMat;
}
static void bench_gmio_stl_read(const char* filepath)
{
// void* mbuffer = std::malloc(512 * 1024);
// gmio_buffer_t buffer = gmio_buffer(mbuffer, 512 * 1024);
char mbuffer[256 * 1024];
gmio_buffer_t buffer = gmio_buffer(&mbuffer[0], sizeof(mbuffer));
aiScene scene;
gmio_stl_mesh_creator_t mesh_creator = { 0 };
mesh_creator.cookie = &scene;
mesh_creator.ascii_begin_solid_func = gmio_assimp_ascii_begin_solid_func;
mesh_creator.binary_begin_solid_func = gmio_assimp_binary_begin_solid;
mesh_creator.add_triangle_func = gmio_assimp_add_triangle;
mesh_creator.end_solid_func = gmio_assimp_end_solid;
int error = gmio_stl_read_file(filepath, &mesh_creator, &buffer);
if (error != GMIO_NO_ERROR)
printf("GeomIO error: 0x%X\n", error);
//std::free(mbuffer);
}
int main(int argc, char** argv)
{
if (argc > 1)
benchmark(&assimp_Importer, "Assimp::Importer::ReadFile()", argc - 1, argv + 1);
return 0;
if (argc > 1) {
benchmark(&bench_assimp_Importer,
"Assimp::Importer::ReadFile()",
argc - 1, argv + 1);
benchmark(&bench_gmio_stl_read,
"gmio_stl_read()",
argc - 1, argv + 1);
}
return 0;
}

View File

@ -1,14 +0,0 @@
include(../../qmake.build/config.pri)
include(occ.pri)
TEMPLATE = app
TARGET = bench_occ$$TARGET_SUFFIX
HEADERS += ../commons/bench_tools.h
SOURCES += \
../commons/bench_tools.c \
main.cpp
LIBS *= -lTKSTL -lTKernel -lTKMath
QMAKE_RPATHDIR *= $$CASCADE_LIB_PATH

View File

@ -1,38 +1,47 @@
extern "C" {
#include "../commons/bench_tools.h"
}
#include <OSD_Path.hxx>
#include <RWStl.hxx>
#include <StlMesh_Mesh.hxx>
#include <StlAPI_Reader.hxx>
#include <TopoDS_Shape.hxx>
static void occ_RWStl_ReadBinary(const char* filepath)
#include <gmio_core/error.h>
#include <gmio_stl/stl_io.h>
#include <gmio_support/occ_libstl.h>
#include "../commons/bench_tools.h"
static void bench_occ_RWStl_ReadFile(const char* filepath)
{
/*Handle_StlMesh_Mesh stlMesh = */RWStl::ReadBinary(OSD_Path(filepath));
RWStl::ReadFile(OSD_Path(filepath));
}
static void occ_StlAPI_Reader(const char* filepath)
static void bench_gmio_stl_read(const char* filepath)
{
StlAPI_Reader reader;
TopoDS_Shape shape;
reader.Read(shape, filepath);
// void* mbuffer = std::malloc(512 * 1024);
// gmio_buffer_t buffer = gmio_buffer(mbuffer, 512 * 1024);
char mbuffer[256 * 1024];
gmio_buffer_t buffer = gmio_buffer(&mbuffer[0], sizeof(mbuffer));
Handle_StlMesh_Mesh mesh = new StlMesh_Mesh;
gmio_stl_mesh_creator_t mesh_creator = gmio_stl_occmesh_creator(mesh);
int error = gmio_stl_read_file(filepath, &mesh_creator, &buffer);
if (error != GMIO_NO_ERROR)
printf("GeomIO error: 0x%X\n", error);
//std::free(mbuffer);
}
int main(int argc, char** argv)
{
if (argc > 1)
benchmark(&occ_RWStl_ReadBinary, "RWStl::ReadBinary()", argc - 1, argv + 1);
if (argc > 1) {
benchmark(&bench_occ_RWStl_ReadFile,
"RWStl::ReadFile()",
argc - 1, argv + 1);
// startTick = std::clock();
// std::cout << "Read with StlAPI_Reader::Read() ..." << std::endl;
// for (int iarg = 1; iarg < argc; ++iarg) {
// StlAPI_Reader reader;
// TopoDS_Shape shape;
// reader.Read(shape, argv[iarg]);
// }
// std::cout << " StlAPI_Reader::Read() read time: " << elapsed_secs(startTick) << "s" << std::endl;
benchmark(&bench_gmio_stl_read,
"gmio_stl_read()",
argc - 1, argv + 1);
}
return 0;
}

View File

@ -1,49 +0,0 @@
# Return the input path re-written using the system-dependent separator
defineReplace(sysPath) {
win*:result = $$replace(1, /, \\)
else:result = $$1
return($$result)
}
use_oce {
CASCADE_INC_PATH = $$CASCADE_ROOT/include/oce
!isEmpty(OCE_VERSION) {
CASCADE_LIB_PATH += -$CASCADE_ROOT/lib/$$OCE_VERSION
}
}
else {
CASCADE_INC_PATH = $$CASCADE_ROOT/inc
}
INCLUDEPATH += $$CASCADE_INC_PATH
linux-*:DEFINES *= HAVE_CONFIG_H \
HAVE_FSTREAM \
HAVE_IOSTREAM \
HAVE_LIMITS_H
win32-*:DEFINES *= WNT
linux-*:DEFINES *= LIN LININTEL OCC_CONVERT_SIGNALS
*-64:DEFINES *= _OCC64
linux-*:CASCADE_LIB_PATH += $$CASCADE_ROOT/lib
CONFIG(debug, debug|release) {
win32-msvc2005:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc8/libd
win32-msvc2008:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc9/lib
win32-msvc2010:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc10/libd
} else {
win32-msvc2005:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc8/lib
win32-msvc2008:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc9/lib
win32-msvc2010:CASCADE_LIB_PATH += $$CASCADE_ROOT/win32/vc10/lib
}
LIBS += $$sysPath($$join(CASCADE_LIB_PATH, " -L", -L))
# There is a weird bug with qmake on windows : it fails to correctly link with TKSTEP209 due to the
# name of library mixing characters and digits.
# Or maybe nmake is the problem ?
# Note : you have to rename TKSTEP209 to TKSTEP_tzn in $$CASCADE_ROOT/win32/lib
win32-msvc* {
OCC_TKSTEP = TKSTEP_tzn
}
else {
OCC_TKSTEP = TKSTEP209
}

View File

@ -1,13 +0,0 @@
include(../../qmake.build/config.pri)
TEMPLATE = app
TARGET = cmd$$TARGET_SUFFIX
QT *= core
HEADERS +=
SOURCES += main.cpp
INCLUDEPATH += ../../src
LIBS += -L../../bin -lfougstl$$TARGET_SUFFIX

View File

@ -1,234 +0,0 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QScopedPointer>
#include <QtCore/QStringList>
#include "abstract_task_progress.h"
#include "libstl/abstract_geometry.h"
#include "libstl/stlb.h"
#include "streams/qt4_stream.h"
#include <fstream>
#include "streams/std_io_stream.h"
#include <cstring>
#include <QtCore/QtDebug>
#include <QtCore/QTime>
#include <QtCore/QVector>
#define USE_QT4STREAM
//#define USE_STDSTREAM
namespace internal {
class ConsoleTaskProgress : public foug::AbstractTaskProgress
{
public:
void handleProgressUpdate()
{
qDebug() << this->progress();
}
};
class DummyGeometryBuilder : public foug::stl::bin::AbstractGeometryBuilder
{
public:
void processHeader(const foug::stl::bin::Header& data)
{
qDebug() << "HEADER : \n" << QString::fromAscii(reinterpret_cast<const char*>(data), 79);
}
void beginTriangles(foug::UInt32 count)
{
m_triangleCounter = 0;
qDebug() << "Triangle count" << count;
}
void processNextTriangle(const foug::stl::Triangle& triangle, foug::UInt16 attributeByteCount)
{
// qDebug() << "TRIANGLE " << m_triangleCounter++;
// qDebug() << " normal" << triangle.normal.x << triangle.normal.y << triangle.normal.z;
// qDebug() << " v1" << triangle.v1.x << triangle.v1.y << triangle.v1.z;
// qDebug() << " v2" << triangle.v2.x << triangle.v2.y << triangle.v2.z;
// qDebug() << " v3" << triangle.v3.x << triangle.v3.y << triangle.v3.z;
// qDebug() << " attr" << attributeByteCount;
}
private:
foug::UInt32 m_triangleCounter;
};
class BasicGeometryHelper :
public foug::stl::AbstractGeometry,
public foug::stl::bin::AbstractGeometryBuilder,
public foug::stl::bin::AbstractGeometryExtraData
{
public:
struct TriangleData
{
foug::stl::Triangle triangle;
foug::UInt16 attributeByteCount;
};
QVector<TriangleData> triangles() const
{
return m_triangles;
}
// -- foug::stl::bin::AbstractGeometryBuilder
void processHeader(const foug::stlb::Header& data)
{
std::memcpy(m_header, data, 80);
}
void beginTriangles(foug::UInt32 count)
{
m_triangles.reserve(count);
m_triangles.clear();
m_triangles.resize(0);
}
void processNextTriangle(const foug::stl::Triangle& triangle, foug::UInt16 attributeByteCount)
{
TriangleData data;
data.triangle = triangle;
data.attributeByteCount = attributeByteCount;
m_triangles.append(data);
}
// -- foug::stl::bin::AbstractGeometryExtraData
void getHeaderData(foug::stl::bin::Header& data) const
{
std::memcpy(data, m_header, 80);
}
foug::UInt16 attributeByteCount(foug::UInt32 triangleIndex) const
{
return m_triangles.at(triangleIndex).attributeByteCount;
}
// -- foug::stl::AbstractGeometry
foug::UInt32 triangleCount() const
{
return m_triangles.size();
}
void getTriangle(foug::UInt32 index, foug::stl::Triangle* triangle) const
{
*triangle = m_triangles.at(index).triangle;
}
private:
QVector<TriangleData> m_triangles;
foug::stl::bin::Header m_header;
};
} // namespace internal
int main(int argc, char** argv)
{
using namespace foug::stl;
QString inputFilePath;
QString outputFilePath;
int iarg = 1;
while (iarg < argc) {
if (!std::strcmp(argv[iarg], "-i"))
inputFilePath = argv[++iarg];
else if (!std::strcmp(argv[iarg], "-o"))
outputFilePath = argv[++iarg];
++iarg;
}
if (inputFilePath.isEmpty()) {
qCritical() << "No input files";
return -1;
}
bin::Io io;
// internal::ConsoleTaskProgress taskProgress;
// io.setTaskProgress(&taskProgress);
// io.setAutoDeleteTaskProgress(false);
#ifdef USE_STDSTREAM
std::ifstream inputFile(inputFilePath.toStdString().c_str(), std::ios::binary);
if (!inputFile.is_open()) {
qCritical() << "Failed to open input file";
return -2;
}
io.setStream(new foug::StdInputStream<std::ifstream>(&inputFile));
#elif defined(USE_QT4STREAM)
QFile inputFile(inputFilePath);
if (!inputFile.open(QIODevice::ReadOnly)) {
qCritical() << "Failed to open input file :" << inputFile.errorString();
return -2;
}
io.setStream(new foug::Qt4Stream(&inputFile));
#endif
{ // BENCH READ
QTime time;
time.start();
internal::DummyGeometryBuilder geomBuilder;
const int benchCount = 100;
for (int i = 0; i < benchCount; ++i) {
io.stream()->seek(0);
io.read(&geomBuilder);
}
qDebug() << QString("Total read time : %1sec").arg(time.elapsed() / 1000.);
qDebug() << QString("Test read time : %1sec")
.arg(time.elapsed() / 1000. / static_cast<double>(benchCount));
}
if (outputFilePath.isEmpty())
return 0;
#ifdef USE_STDSTREAM
std::ofstream outputFile(outputFilePath.toStdString().c_str(), std::ios::out | std::ios::binary);
//std::ofstream outputFile(outputFilePath.toStdString().c_str(), std::ios::binary);
if (!outputFile.is_open()) {
qCritical() << "Failed to open output file";
return -3;
}
#elif defined(USE_QT4STREAM)
QFile outputFile(outputFilePath);
if (!outputFile.open(QIODevice::WriteOnly)) {
qCritical() << "Failed to open output file :" << outputFile.errorString();
return -3;
}
#endif
internal::BasicGeometryHelper geomHelper;
{ // READ GEOMETRY
io.stream()->seek(0);
io.read(&geomHelper);
}
{ // BENCH WRITE
#ifdef USE_STDSTREAM
io.setStream(new foug::StdOutputStream<std::ofstream>(&outputFile));
#elif defined(USE_QT4STREAM)
io.setStream(new foug::Qt4Stream(&outputFile));
#endif
QTime time;
time.start();
const int benchCount = 100;
for (int i = 0; i < benchCount; ++i) {
io.stream()->seek(0);
io.write(geomHelper, &geomHelper);
}
qDebug() << QString("Total write time : %1sec").arg(time.elapsed() / 1000.);
qDebug() << QString("Test write time : %1sec")
.arg(time.elapsed() / 1000. / static_cast<double>(benchCount));
}
return 0;
}

View File

@ -7,7 +7,8 @@ float elapsed_secs(clock_t start_tick)
return (float)((clock() - start_tick) / (float)CLOCKS_PER_SEC);
}
void benchmark(void (*func)(const char*), const char* title, int argc, char** argv)
void benchmark(
void (*func)(const char*), const char* title, int argc, char** argv)
{
const clock_t start_tick = clock();
int iarg;

View File

@ -3,8 +3,15 @@
#include <time.h>
#include <gmio_core/global.h>
GMIO_C_LINKAGE_BEGIN
float elapsed_secs(clock_t start_tick);
void benchmark(void (*func)(const char*), const char* title, int argc, char** argv);
void benchmark(
void (*func)(const char*), const char* title, int argc, char** argv);
GMIO_C_LINKAGE_END
#endif /* BENCH_TOOLS_H */

View File

@ -1,7 +0,0 @@
TEMPLATE = subdirs
SUBDIRS += \
#bench_occ \
bench_libstl \
#bench_assimp \
#c-lib