// ======================================================================== // // Copyright 2009-2014 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // // you may not use this file except in compliance with the License. // // You may obtain a copy of the License at // // // // http://www.apache.org/licenses/LICENSE-2.0 // // // // Unless required by applicable law or agreed to in writing, software // // distributed under the License is distributed on an "AS IS" BASIS, // // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // // limitations under the License. // // ======================================================================== // #include "sys/platform.h" #include "sys/ref.h" #include "embree2/rtcore.h" #include "embree2/rtcore_ray.h" #include "../kernels/common/default.h" #include "../kernels/common/raystream_log.h" #include "sys/intrinsics.h" #include "sys/thread.h" #include "sys/sysinfo.h" #include "sys/sync/barrier.h" #include "sys/sync/mutex.h" #include "sys/sync/condition.h" #include #include #include #define DBG(x) #define SSC_MARK(mark_value) \ {__asm mov ebx, mark_value} \ {__asm _emit 0x64} \ {__asm _emit 0x67} \ {__asm _emit 0x90} namespace embree { struct RayStreamStats { size_t numTotalRays; size_t numRayPackets; size_t numIntersectRayPackets; size_t numOccludedRayPackets; size_t numIntersectRays; size_t numOccludedRays; size_t num4widePackets; size_t num8widePackets; RayStreamStats() { memset(this,0,sizeof(RayStreamStats)); } void add(RayStreamLogger::LogRay16 &r) { size_t numRays = r.numRays; numRayPackets++; numTotalRays += numRays; if (r.type == RayStreamLogger::RAY_INTERSECT) { numIntersectRayPackets++; numIntersectRays += numRays; } else if (r.type == RayStreamLogger::RAY_OCCLUDED) { numOccludedRayPackets++; numOccludedRays += numRays; } else FATAL("unknown log ray type"); num4widePackets += (numRays+3)/4; num8widePackets += (numRays+7)/8; } void add(RayStreamLogger::LogRay4 &r) { size_t numRays = r.numRays; numRayPackets++; numTotalRays += numRays; if (r.type == RayStreamLogger::RAY_INTERSECT) { numIntersectRayPackets++; numIntersectRays += numRays; } else if (r.type == RayStreamLogger::RAY_OCCLUDED) { numOccludedRayPackets++; numOccludedRays += numRays; } else FATAL("unknown log ray type"); } void add(RayStreamLogger::LogRay8 &r) { size_t numRays = r.numRays; numRayPackets++; numTotalRays += numRays; if (r.type == RayStreamLogger::RAY_INTERSECT) { numIntersectRayPackets++; numIntersectRays += numRays; } else if (r.type == RayStreamLogger::RAY_OCCLUDED) { numOccludedRayPackets++; numOccludedRays += numRays; } else FATAL("unknown log ray type"); num4widePackets += (numRays+3)/4; } void add(RayStreamLogger::LogRay1 &r) { numRayPackets++; numTotalRays ++; if (r.type == RayStreamLogger::RAY_INTERSECT) { numIntersectRayPackets++; numIntersectRays++; } else if (r.type == RayStreamLogger::RAY_OCCLUDED) { numOccludedRayPackets++; numOccludedRays++; } else FATAL("unknown log ray type"); num4widePackets += 1; num8widePackets += 1; } void print(size_t simd_width) { std::cout << "numTotalRays = " << numTotalRays << std::endl; std::cout << "numRayPackets = " << numRayPackets << std::endl; std::cout << "numIntersectionRays = " << numIntersectRays << " [" << 100. * (double)numIntersectRays / numTotalRays << "%]" << std::endl; std::cout << "numOcclusionRays = " << numOccludedRays << " [" << 100. * (double)numOccludedRays / numTotalRays << "%]" << std::endl; if (simd_width > 1) { std::cout << "avg. intersect " << simd_width << "-wide packet utilization = " << 100. * (double)numIntersectRays / (numIntersectRayPackets * (double)simd_width) << "%" << std::endl; std::cout << "avg. occluded " << simd_width << "-wide packet utilization = " << 100. * (double)numOccludedRays / (numOccludedRayPackets * (double)simd_width) << "%" << std::endl; std::cout << "avg. total " << simd_width << "-wide packet utilization = " << 100. * (double)numTotalRays / (numRayPackets * (double)simd_width) << "%" << std::endl; } if (simd_width == 16) { std::cout << "avg. 4-wide packet utilization = " << 100. * (double)numTotalRays / (num4widePackets * 4.) << "%" << std::endl; std::cout << "avg. 8-wide packet utilization = " << 100. * (double)numTotalRays / (num8widePackets * 8.) << "%" << std::endl; } } }; struct RetraceTask { RTCScene scene; void *raydata; void *raydata_verify; size_t numLogRayStreamElements; bool check; }; /* configuration */ #if !defined(__MIC__) RTCAlgorithmFlags aflags = (RTCAlgorithmFlags) (RTC_INTERSECT1 | RTC_INTERSECT4 | RTC_INTERSECT8); static std::string g_rtcore = "verbose=2"; #else RTCAlgorithmFlags aflags = (RTCAlgorithmFlags) (RTC_INTERSECT1 | RTC_INTERSECT16); static std::string g_rtcore = "verbose=2,threads=1"; #endif /* vertex and triangle layout */ struct Vertex { float x,y,z,a; }; struct Triangle { int v0, v1, v2; }; __forceinline std::ostream &operator<<(std::ostream &o, const Vertex &v) { o << "vtx " << v.x << " " << v.y << " " << v.z << " " << v.a << std::endl; return o; } __forceinline std::ostream &operator<<(std::ostream &o, const Triangle &t) { o << "tri " << t.v0 << " " << t.v1 << " " << t.v2 << std::endl; return o; } static AlignedAtomicCounter32 g_counter = 0; static bool g_check = false; static bool g_sde = false; static size_t g_threadCount = 1; static size_t g_frames = 1; static size_t g_simd_width = 0; static AlignedAtomicCounter32 g_rays_traced = 0; static AlignedAtomicCounter32 g_rays_traced_diff = 0; static std::vector g_threads; #if !defined(__MIC__) static BarrierSys g_barrier; #else static LinearBarrierActive g_barrier; #endif static bool g_exitThreads = false; static RetraceTask g_retraceTask; static MutexSys g_mutex; #if defined(__MIC__) static std::string g_binaries_path = "/home/micuser/"; #else static std::string g_binaries_path = "./"; #endif #define AssertNoError() \ if (rtcGetError() != RTC_NO_ERROR) return false; #define AssertAnyError() \ if (rtcGetError() == RTC_NO_ERROR) return false; #define AssertError(code) \ if (rtcGetError() != code) return false; static void parseCommandLine(int argc, char** argv) { for (int i=1; i void *loadRayStreamData(std::string &rayStreamFile, size_t &numLogRayStreamElements) { std::ifstream rayStreamData; rayStreamData.open(rayStreamFile.c_str(),std::ios::in | std::ios::binary); if (!rayStreamData) { FATAL("could not open raystream data file"); } rayStreamData.seekg(0, std::ios::beg); std::streampos begin = rayStreamData.tellg(); rayStreamData.seekg(0, std::ios::end); std::streampos end = rayStreamData.tellg(); size_t fileSize = end - begin; char *ptr = (char*)os_malloc(fileSize); rayStreamData.seekg(0, std::ios::beg); rayStreamData.read(ptr,fileSize); numLogRayStreamElements = fileSize / sizeof(T); rayStreamData.close(); return ptr; } template RayStreamStats analyseRayStreamData(void *r, size_t numLogRayStreamElements) { RayStreamStats stats; std::cout << "numLogRayStreamElements " << numLogRayStreamElements << std::endl; for (size_t i=0;i void print(const char *name, T *ptr, const size_t N) { std::cout << name << " "; for (size_t i=0;i void print_packet(T &t) { const size_t elements = sizeof(T) / (18 * 4); // 18 elements, and 4 bytes per element print("orgx" ,t.orgx,elements); print("orgy" ,t.orgy,elements); print("orgz" ,t.orgz,elements); print("dirx" ,t.dirx,elements); print("diry" ,t.diry,elements); print("dirz" ,t.dirz,elements); print("tnear" ,t.tnear,elements); print("tfar" ,t.tfar,elements); print("primID",t.primID,elements); print("geomID",t.geomID,elements); print("u" ,t.u,elements); print("v" ,t.v,elements); print("Ngx" ,t.Ngx,elements); print("Ngy" ,t.Ngy,elements); print("Ngz" ,t.Ngz,elements); } template size_t check_ray_packets(const unsigned int m_valid, T &start, T &end) { size_t diff = 0; const size_t elements = sizeof(T) / (18 * 4); // 18 elements, and 4 bytes per element for (size_t i=0;i void retrace_loop() { size_t rays = 0; size_t diff = 0; while(1) { size_t global_index = g_counter.add(RAY_BLOCK_SIZE); if (global_index >= g_retraceTask.numLogRayStreamElements) break; size_t startID = global_index; size_t endID = min(g_retraceTask.numLogRayStreamElements,startID+RAY_BLOCK_SIZE); for (size_t index=startID;index(raydata[index].m_valid, raydata[index].ray4, raydata_verify[index].ray4); } else if (SIMD_WIDTH == 8) { RayStreamLogger::LogRay8 *raydata = (RayStreamLogger::LogRay8 *)g_retraceTask.raydata; RayStreamLogger::LogRay8 *raydata_verify = (RayStreamLogger::LogRay8 *)g_retraceTask.raydata_verify; RTCRay8 &ray8 = raydata[index].ray8; __aligned(64) sseb valid[2]; valid[0] = sseb((int)(raydata[index].m_valid & 0xf)); valid[1] = sseb((int)(raydata[index].m_valid>>4)); rays += raydata[index].numRays; if (raydata[index].type == RayStreamLogger::RAY_INTERSECT) rtcIntersect8(valid,g_retraceTask.scene,ray8); else rtcOccluded8(valid,g_retraceTask.scene,ray8); if (unlikely(g_check)) diff += check_ray_packets(raydata[index].m_valid, raydata[index].ray8, raydata_verify[index].ray8); } #endif else if (SIMD_WIDTH == 16) { RayStreamLogger::LogRay16 *raydata = (RayStreamLogger::LogRay16 *)g_retraceTask.raydata; RayStreamLogger::LogRay16 *raydata_verify = (RayStreamLogger::LogRay16 *)g_retraceTask.raydata_verify; #if defined(__MIC__) RTCRay16 &ray16 = raydata[index].ray16; mic_i valid = select((mic_m)raydata[index].m_valid,mic_i(-1),mic_i(0)); rays += raydata[index].numRays; //raydata[index+1].prefetchL2(); if (raydata[index].type == RayStreamLogger::RAY_INTERSECT) rtcIntersect16(&valid,g_retraceTask.scene,ray16); else rtcOccluded16(&valid,g_retraceTask.scene,ray16); #endif if (unlikely(g_check)) diff += check_ray_packets(raydata[index].m_valid, raydata[index].ray16, raydata_verify[index].ray16); } } } if (unlikely(g_check && diff)) g_rays_traced_diff.add(diff); g_rays_traced.add(rays); } void renderMainLoop(size_t id) { switch(g_simd_width) { case 1: retrace_loop<1>(); break; case 4: retrace_loop<4>(); break; case 8: retrace_loop<8>(); break; case 16: retrace_loop<16>(); break; }; } void threadMainLoop(void *ptr) { size_t id = (size_t)ptr; setAffinity(id); DBG( g_mutex.lock(); DBG_PRINT(id); g_mutex.unlock(); ); while(1) { g_barrier.wait(id,g_threadCount); if (g_exitThreads) break; renderMainLoop(id); g_barrier.wait(id,g_threadCount); } } void createThreads(size_t numThreads) { for (size_t i=1; i(rayStreamFileName, numLogRayStreamElements); if (g_check) raydata_verify = loadRayStreamData(rayStreamVerifyFileName, numLogRayStreamElementsVerify); break; case 4: raydata = loadRayStreamData(rayStreamFileName, numLogRayStreamElements); if (g_check) raydata_verify = loadRayStreamData(rayStreamVerifyFileName, numLogRayStreamElementsVerify); break; case 8: raydata = loadRayStreamData(rayStreamFileName, numLogRayStreamElements); if (g_check) raydata_verify = loadRayStreamData(rayStreamVerifyFileName, numLogRayStreamElementsVerify); break; case 16: raydata = loadRayStreamData(rayStreamFileName, numLogRayStreamElements); if (g_check) raydata_verify = loadRayStreamData(rayStreamVerifyFileName, numLogRayStreamElementsVerify); break; default: FATAL("unknown SIMD width"); } std::cout << "done" << std::endl << std::flush; if (g_check) if (numLogRayStreamElements != numLogRayStreamElementsVerify) FATAL("numLogRayStreamElements != numLogRayStreamElementsVerify"); /* analyse ray stream data */ std::cout << "analyse ray stream:" << std::endl << std::flush; RayStreamStats stats; switch(g_simd_width) { case 1: stats = analyseRayStreamData(raydata,numLogRayStreamElements); break; case 4: stats = analyseRayStreamData(raydata,numLogRayStreamElements); break; case 8: stats = analyseRayStreamData(raydata,numLogRayStreamElements); break; case 16: stats = analyseRayStreamData(raydata,numLogRayStreamElements); break; } stats.print(g_simd_width); #if defined(RTCORE_ENABLE_RAYSTREAM_LOGGER) FATAL("ray stream logger still active, must be disabled to run 'retrace'"); #endif /* init global tasking barrier */ g_barrier.init( g_threadCount ); g_retraceTask.scene = scene; g_retraceTask.raydata = raydata; g_retraceTask.raydata_verify = raydata_verify; g_retraceTask.numLogRayStreamElements = numLogRayStreamElements; g_retraceTask.check = g_check; std::cout << "using " << g_threadCount << " threads for retracing rays" << std::endl << std::flush; createThreads(g_threadCount); /* retrace ray packets */ DBG_PRINT( g_threadCount ); std::cout << "Retracing logged rays:" << std::endl << std::flush; double avg_time = 0; double mrays_sec = 0; for (size_t i=0;i time " << 1000. * dt << " " << 1. / dt << " fps " << "ms " << g_rays_traced / dt / 1000000. << " mrays/sec" << std::endl; #endif g_barrier.wait(0,g_threadCount); if (g_sde) { #if defined(__INTEL_COMPILER) __asm { int 3 }; SSC_MARK(222); #endif } if (unlikely(g_check)) std::cout << g_rays_traced_diff << " rays differ in result (" << 100. * g_rays_traced_diff / g_rays_traced << "%)" << std::endl; } std::cout << "rays " << g_rays_traced << " avg. mrays/sec = " << mrays_sec / (double)g_frames << std::endl; std::cout << "freeing threads..." << std::flush; g_exitThreads = true; g_barrier.wait(0,g_threadCount); std::cout << "done" << std::endl << std::flush; /* done */ rtcExit(); return 0; } } int main(int argc, char** argv) { try { return embree::main(argc, argv); } catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return 1; } catch (...) { std::cout << "Error: unknown exception caught." << std::endl; return 1; } }