mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 19:04:32 +02:00
adding threading and read write lock tests
This commit is contained in:
parent
9411519dc9
commit
14f8245dd8
10 changed files with 387 additions and 0 deletions
36
tests/threads/CMakeLists.txt
Normal file
36
tests/threads/CMakeLists.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
if (WIN32)
|
||||
cmake_policy (SET CMP0020 NEW)
|
||||
endif (WIN32)
|
||||
|
||||
set(TARGET_NAME threads-tests)
|
||||
|
||||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||
auto_mtc(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Core)
|
||||
|
||||
#include glm
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
# link in the shared libraries
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
IF (WIN32)
|
||||
#target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
65
tests/threads/src/SampleReadThread.cpp
Normal file
65
tests/threads/src/SampleReadThread.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// SampleReadThread.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree.
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SharedResource.h"
|
||||
#include "SampleReadThread.h"
|
||||
|
||||
SampleReadThread::SampleReadThread(SharedResource* theResource, int id) :
|
||||
_theResource(theResource),
|
||||
_myID(id) {
|
||||
}
|
||||
|
||||
bool SampleReadThread::process() {
|
||||
const quint64 FRAME_RATE = 60;
|
||||
const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps
|
||||
|
||||
quint64 start = usecTimestampNow();
|
||||
_theResource->lockForRead();
|
||||
quint64 end = usecTimestampNow();
|
||||
quint64 elapsed = end - start;
|
||||
|
||||
int theValue = _theResource->getValue();
|
||||
|
||||
bool wantDebugging = true;
|
||||
if (wantDebugging) {
|
||||
qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" <<
|
||||
" _theResource->getValue()=" << theValue;
|
||||
}
|
||||
|
||||
quint64 startWork = usecTimestampNow();
|
||||
{
|
||||
const int LOTS_OF_OPERATIONS = 100000;
|
||||
for(int i = 0; i < LOTS_OF_OPERATIONS; i++) {
|
||||
float x = rand();
|
||||
float y = rand();
|
||||
float z = x * y;
|
||||
}
|
||||
}
|
||||
quint64 endWork = usecTimestampNow();
|
||||
quint64 elapsedWork = endWork - startWork;
|
||||
qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs";
|
||||
|
||||
_theResource->unlock();
|
||||
|
||||
|
||||
if (isStillRunning()) {
|
||||
if (elapsed < USECS_PER_FRAME) {
|
||||
quint64 sleepFor = USECS_PER_FRAME - elapsed;
|
||||
usleep(sleepFor);
|
||||
} else {
|
||||
usleep(5); // sleep at least a little
|
||||
}
|
||||
}
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
31
tests/threads/src/SampleReadThread.h
Normal file
31
tests/threads/src/SampleReadThread.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// SampleReadThread.h
|
||||
// tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__SampleReadThread__
|
||||
#define __interface__SampleReadThread__
|
||||
|
||||
#include <GenericThread.h>
|
||||
|
||||
class SharedResource;
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class SampleReadThread : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SampleReadThread(SharedResource* theResource, int id);
|
||||
|
||||
protected:
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
||||
private:
|
||||
SharedResource* _theResource;
|
||||
int _myID;
|
||||
};
|
||||
|
||||
#endif // __interface__SampleReadThread__
|
47
tests/threads/src/SampleWriteThread.cpp
Normal file
47
tests/threads/src/SampleWriteThread.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// SampleWriteThread.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree.
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SharedResource.h"
|
||||
#include "SampleWriteThread.h"
|
||||
|
||||
SampleWriteThread::SampleWriteThread(SharedResource* theResource) :
|
||||
_theResource(theResource) {
|
||||
}
|
||||
|
||||
bool SampleWriteThread::process() {
|
||||
const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second.
|
||||
|
||||
quint64 start = usecTimestampNow();
|
||||
_theResource->lockForWrite();
|
||||
quint64 end = usecTimestampNow();
|
||||
quint64 elapsed = end - start;
|
||||
|
||||
int theValue = _theResource->incrementValue();
|
||||
|
||||
bool wantDebugging = false;
|
||||
if (wantDebugging) {
|
||||
qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" <<
|
||||
" _theResource->incrementValue()=" << theValue;
|
||||
}
|
||||
_theResource->unlock();
|
||||
|
||||
|
||||
if (isStillRunning()) {
|
||||
if (elapsed < USECS_PER_OPERATION) {
|
||||
quint64 sleepFor = USECS_PER_OPERATION - elapsed;
|
||||
usleep(sleepFor);
|
||||
}
|
||||
}
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
30
tests/threads/src/SampleWriteThread.h
Normal file
30
tests/threads/src/SampleWriteThread.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// SampleWriteThread.h
|
||||
// tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__SampleWriteThread__
|
||||
#define __interface__SampleWriteThread__
|
||||
|
||||
#include <GenericThread.h>
|
||||
|
||||
class SharedResource;
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class SampleWriteThread : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SampleWriteThread(SharedResource* theResource);
|
||||
|
||||
protected:
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
||||
private:
|
||||
SharedResource* _theResource;
|
||||
};
|
||||
|
||||
#endif // __interface__SampleWriteThread__
|
38
tests/threads/src/SharedResource.cpp
Normal file
38
tests/threads/src/SharedResource.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// SharedResource.cpp
|
||||
// tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SharedResource.h"
|
||||
|
||||
const int MOVING_AVERAGE_SAMPLES = 10000;
|
||||
|
||||
SharedResource::SharedResource() :
|
||||
_value(0),
|
||||
_lockAverage(MOVING_AVERAGE_SAMPLES),
|
||||
_lockForReadAverage(MOVING_AVERAGE_SAMPLES),
|
||||
_lockForWriteAverage(MOVING_AVERAGE_SAMPLES)
|
||||
{
|
||||
};
|
||||
|
||||
void SharedResource::lockForRead() {
|
||||
quint64 start = usecTimestampNow();
|
||||
_lock.lockForRead();
|
||||
quint64 end = usecTimestampNow();
|
||||
quint64 elapsed = end - start;
|
||||
_lockForReadAverage.updateAverage(elapsed);
|
||||
_lockAverage.updateAverage(elapsed);
|
||||
}
|
||||
void SharedResource::lockForWrite() {
|
||||
quint64 start = usecTimestampNow();
|
||||
_lock.lockForWrite();
|
||||
quint64 end = usecTimestampNow();
|
||||
quint64 elapsed = end - start;
|
||||
_lockForWriteAverage.updateAverage(elapsed);
|
||||
_lockAverage.updateAverage(elapsed);
|
||||
}
|
40
tests/threads/src/SharedResource.h
Normal file
40
tests/threads/src/SharedResource.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// SharedResource.h
|
||||
// tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__SharedResource__
|
||||
#define __interface__SharedResource__
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <SimpleMovingAverage.h>
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class SharedResource {
|
||||
public:
|
||||
SharedResource();
|
||||
|
||||
void lockForRead();
|
||||
void lockForWrite();
|
||||
void unlock() { _lock.unlock(); }
|
||||
|
||||
int getValue() const { return _value; }
|
||||
int incrementValue() { return ++_value; }
|
||||
|
||||
float getAverageLockTime() const { return _lockAverage.getAverage(); }
|
||||
float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); }
|
||||
float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); }
|
||||
|
||||
private:
|
||||
QReadWriteLock _lock;
|
||||
int _value;
|
||||
SimpleMovingAverage _lockAverage;
|
||||
SimpleMovingAverage _lockForReadAverage;
|
||||
SimpleMovingAverage _lockForWriteAverage;
|
||||
};
|
||||
|
||||
#endif // __interface__SharedResource__
|
73
tests/threads/src/ThreadsTests.cpp
Normal file
73
tests/threads/src/ThreadsTests.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// ThreadsTests.cpp
|
||||
// thread-tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <GenericThread.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SampleReadThread.h"
|
||||
#include "SampleWriteThread.h"
|
||||
#include "SharedResource.h"
|
||||
#include "ThreadsTests.h"
|
||||
|
||||
|
||||
void ThreadsTests::runAllTests() {
|
||||
qDebug() << "START ThreadsTests::runAllTests()";
|
||||
|
||||
const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes
|
||||
const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second
|
||||
quint64 start = usecTimestampNow();
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
SharedResource resource;
|
||||
|
||||
const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac.
|
||||
QVector<SampleReadThread*> readThreads;
|
||||
for(int i = 0; i < NUMBER_OF_READERS; i++) {
|
||||
SampleReadThread* newReader = new SampleReadThread(&resource, i);
|
||||
newReader->initialize();
|
||||
readThreads.append(newReader);
|
||||
}
|
||||
|
||||
SampleWriteThread write(&resource);
|
||||
write.initialize();
|
||||
|
||||
while(now - start < TOTAL_RUN_TIME) {
|
||||
float elapsed = (float)(now - start) / (float)USECS_PER_SECOND;
|
||||
qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds";
|
||||
qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs";
|
||||
qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs";
|
||||
qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs";
|
||||
qDebug() << " resource.value:" << resource.getValue();
|
||||
|
||||
|
||||
usleep(MAIN_THREAD_SLEEP);
|
||||
now = usecTimestampNow();
|
||||
}
|
||||
write.terminate();
|
||||
|
||||
foreach(SampleReadThread* readThread, readThreads) {
|
||||
readThread->terminate();
|
||||
delete readThread;
|
||||
}
|
||||
readThreads.clear();
|
||||
|
||||
qDebug() << "DONE running...";
|
||||
qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs";
|
||||
qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs";
|
||||
qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs";
|
||||
qDebug() << " resource.value:" << resource.getValue();
|
||||
|
||||
qDebug() << "END ThreadsTests::runAllTests()";
|
||||
|
||||
qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX;
|
||||
qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount();
|
||||
|
||||
}
|
16
tests/threads/src/ThreadsTests.h
Normal file
16
tests/threads/src/ThreadsTests.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// ThreadsTests.h
|
||||
// threads-tests
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014.03.17
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __tests__ThreadsTests__
|
||||
#define __tests__ThreadsTests__
|
||||
|
||||
namespace ThreadsTests {
|
||||
void runAllTests();
|
||||
}
|
||||
|
||||
#endif // __tests__ThreadsTests__
|
11
tests/threads/src/main.cpp
Normal file
11
tests/threads/src/main.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// main.cpp
|
||||
// threads-tests
|
||||
//
|
||||
|
||||
#include "ThreadsTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ThreadsTests::runAllTests();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue