Skip to content

Commit

Permalink
Merge branch 'dev' adding custom allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
dougbinks committed Nov 5, 2019
2 parents be50784 + a486e09 commit 407f793
Show file tree
Hide file tree
Showing 8 changed files with 471 additions and 67 deletions.
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ if( ENKITS_BUILD_EXAMPLES )
add_executable( ExternalTaskThread example/ExternalTaskThread.cpp )
target_link_libraries(ExternalTaskThread enkiTS )

add_executable( CustomAllocator example/CustomAllocator.cpp )
target_link_libraries(CustomAllocator enkiTS )

if( ENKITS_BUILD_C_INTERFACE )
add_executable( ParallelSum_c example/ParallelSum_c.c )
target_link_libraries(ParallelSum_c enkiTS )
Expand All @@ -113,5 +116,8 @@ if( ENKITS_BUILD_C_INTERFACE )
add_executable( ExternalTaskThread_c example/ExternalTaskThread_c.c )
target_link_libraries(ExternalTaskThread_c enkiTS )

add_executable( CustomAllocator_c example/CustomAllocator_c.c )
target_link_libraries(CustomAllocator_c enkiTS )

endif()
endif()
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Support development of enkiTS through our [Patreon](https://www.patreon.com/enkisoftware)
Support development of enkiTS through [Github Sponsors](https://github.com/sponsors/dougbinks) or [Patreon](https://www.patreon.com/enkisoftware)

[<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="Become a Patron" width="150"/>](https://www.patreon.com/enkisoftware)
[<img src="https://img.shields.io/static/v1?logo=github&label=Github&message=Sponsor&color=#ea4aaa" width="200"/>](https://github.com/sponsors/dougbinks) [<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="Become a Patron" width="150"/>](https://www.patreon.com/enkisoftware)

# enkiTS
[![Build Status for branch: master](https://travis-ci.org/dougbinks/enkiTS.svg?branch=master)](https://travis-ci.org/dougbinks/enkiTS)
Expand Down Expand Up @@ -45,7 +45,8 @@ For cmake, on Windows / Mac OS X / Linux with cmake installed, open a prompt in
1. *Up-front Allocation friendly* - enkiTS is designed for zero allocations during scheduling.
1. *Can pin tasks to a given thread* - enkiTS can schedule a task which will only be run on the specified thread.
1. *Can set task priorities* - Up to 5 task priorities can be configured via define ENKITS_TASK_PRIORITIES_NUM (defaults to 3). Higher priority tasks are run before lower priority ones.
1. **NEW** *Can register external threads to use with enkiTS* - Can configure enkiTS with numExternalTaskThreads which can be registered to use with the enkiTS API.
1. *Can register external threads to use with enkiTS* - Can configure enkiTS with numExternalTaskThreads which can be registered to use with the enkiTS API.
1. **NEW** *Custom allocator API* - can configure enkiTS with custom allocators, see [example/CustomAllocator.cpp](example/CustomAllocator.cpp) and [example/CustomAllocator_c.c](example/CustomAllocator_c.c).

## Usage

Expand Down
97 changes: 97 additions & 0 deletions example/CustomAllocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2019 Doug Binks
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.

#include "TaskScheduler.h"

#include <stdio.h>
#include <thread>

using namespace enki;

TaskScheduler g_TS;

struct ParallelTaskSet : ITaskSet
{
virtual void ExecuteRange( TaskSetPartition range_, uint32_t threadnum_ )
{
printf(" This could run on any thread, currently thread %d\n", threadnum_);
}
};

struct CustomData
{
const char* domainName;
size_t totalAllocations;
};

void* CustomAllocFunc( size_t align_, size_t size_, void* userData_, const char* file_, int line_ )
{
CustomData* data = (CustomData*)userData_;
data->totalAllocations += size_;

// We don't need to use this macro as file_ and line_ will be valid and printable just not useful
// But for this example it makes prettier output :)
#ifdef ENKI_CUSTOM_ALLOC_FILE_AND_LINE
printf("Allocating %g bytes in domain %s, total %g. File %s, line %d.\n",
(double)size_, data->domainName, (double)data->totalAllocations, file_, line_ );
#else
(void)file_; (void)line_;
printf("Allocating %g bytes in domain %s, total %g.\n",
(double)size_, data->domainName, (double)data->totalAllocations );
#endif

return DefaultAllocFunc( align_, size_, userData_, file_, line_ );
};

void CustomFreeFunc( void* ptr_, size_t size_, void* userData_, const char* file_, int line_ )
{
CustomData* data = (CustomData*)userData_;
data->totalAllocations -= size_;

// we don't need to use this macro as file_ and line_ will be valid and printable just not useful
// But for this example it makes prettier output :)
#ifdef ENKI_CUSTOM_ALLOC_FILE_AND_LINE
printf("Freeing %p in domain %s, total %g. File %s, line %d.\n",
ptr_, data->domainName, (double)data->totalAllocations, file_, line_ );
#else
(void)file_; (void)line_;
printf("Freeing %p in domain %s, total %g.\n",
ptr_, data->domainName, (double)data->totalAllocations );
#endif

DefaultFreeFunc( ptr_, size_, userData_, file_, line_ );
};


int main(int argc, const char * argv[])
{
enki::TaskSchedulerConfig config;
config.customAllocator.alloc = CustomAllocFunc;
config.customAllocator.free = CustomFreeFunc;
CustomData data{ "enkITS", 0 };
config.customAllocator.userData = &data;

g_TS.Initialize( config );

ParallelTaskSet task;
g_TS.AddTaskSetToPipe( &task );
g_TS.WaitforTask( &task );
g_TS.WaitforAllAndShutdown(); // ensure we shutdown before user data is destroyed.

return 0;
}
93 changes: 93 additions & 0 deletions example/CustomAllocator_c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2019 Doug Binks
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.

#include "TaskScheduler_c.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

enkiTaskScheduler* pETS;
enkiTaskSet* pParallelTask;

size_t totalAllocations = 0;

void ParallelFunc( uint32_t start_, uint32_t end, uint32_t threadnum_, void* pArgs_ )
{
// do something
printf("ParallelFunc running on thread %d (could be any thread)\n", threadnum_ );
}

void* CustomAllocFunc( size_t align_, size_t size_, void* userData_, const char* file_, int line_ )
{
(void)align_; // for example ignoring alignment
totalAllocations += size_;

// We don't need to use this macro as file_ and line_ will be valid and printable just not useful
// But for this example it makes prettier output :)
#ifdef ENKI_CUSTOM_ALLOC_FILE_AND_LINE
printf("Allocating %g bytes in domain %s, total %g. File %s, line %d.\n",
(double)size_, (const char*)userData_, (double)totalAllocations, file_, line_ );
#else
(void)file_; (void)line_;
printf("Allocating %g bytes in domain %s, total %g.\n",
(double)size_, (const char*)userData_, (double)totalAllocations );
#endif

return enkiDefaultAllocFunc( align_, size_, userData_, file_, line_ );
};

void CustomFreeFunc( void* ptr_, size_t size_, void* userData_, const char* file_, int line_ )
{
totalAllocations -= size_;

// We don't need to use this macro as file_ and line_ will be valid and printable just not useful
// But for this example it makes prettier output :)
#ifdef ENKI_CUSTOM_ALLOC_FILE_AND_LINE
printf("Freeing %p in domain %s, total %g. File %s, line %d.\n",
ptr_, (const char*)userData_, (double)totalAllocations, file_, line_ );
#else
(void)file_; (void)line_;
printf("Freeing %p in domain %s, total %g.\n",
ptr_, (const char*)userData_, (double)totalAllocations );
#endif

enkiDefaultFreeFunc( ptr_, size_, userData_, file_, line_ );
};


int main(int argc, const char * argv[])
{
struct enkiCustomAllocator customAllocator;

customAllocator.alloc = CustomAllocFunc;
customAllocator.free = CustomFreeFunc;
customAllocator.userData = (void*)"enkiTS";

pETS = enkiNewTaskSchedulerWithCustomAllocator( customAllocator );
enkiInitTaskScheduler( pETS );

pParallelTask = enkiCreateTaskSet( pETS, ParallelFunc );

enkiAddTaskSetToPipe( pETS, pParallelTask, NULL, 1);
enkiWaitForTaskSet( pETS, pParallelTask );

enkiDeleteTaskSet( pParallelTask );

enkiDeleteTaskScheduler( pETS );
}
Loading

0 comments on commit 407f793

Please sign in to comment.