1 /** 2 Module contains multithreated allcoators. Few of them with similar interface. 3 */ 4 module mutils.container_shared.shared_allocator; 5 6 import std.stdio; 7 import std.conv:emplace; 8 import std.experimental.allocator; 9 import std.experimental.allocator.mallocator; 10 11 import mutils.job_manager.shared_utils; 12 import mutils.job_manager.utils; 13 import mutils.container.vector; 14 15 16 class MyMallocator{ 17 shared Mallocator allocator; 18 this(){ 19 allocator=Mallocator.instance; 20 } 21 auto make(T,Args...)(auto ref Args args){ 22 return allocator.make!T(args); 23 } 24 void dispose(T)(ref T* obj){ 25 allocator.dispose(obj); 26 //obj=T.init; 27 } 28 } 29 class MyGcAllcoator{ 30 auto make(T,Args...)(auto ref Args args){ 31 auto var=new T(args); 32 import core.memory; 33 GC.addRoot(var); 34 return var; 35 } 36 void dispose(T)(ref T* obj){ 37 import core.memory; 38 GC.removeRoot(obj); 39 //obj=T.init; 40 } 41 } 42 43 import core.atomic; 44 import std.random:uniform; 45 46 47 48 class BucketAllocator(uint bucketSize){ 49 static assert(bucketSize>=8); 50 enum shared Bucket* invalidValue=cast(shared Bucket*)858567; 51 52 static struct Bucket{ 53 union{ 54 void[bucketSize] data; 55 Bucket* next; 56 } 57 } 58 enum bucketsNum=128; 59 60 61 static struct BucketsArray{ 62 @nogc: 63 Bucket[bucketsNum] buckets; 64 shared Bucket* empty; 65 void initialize() shared { 66 shared Bucket* last; 67 foreach(i,ref bucket;buckets){ 68 bucket.next=last; 69 last=&bucket; 70 } 71 empty=cast(shared Bucket*)last; 72 } 73 uint freeSlots()shared { 74 uint i; 75 shared Bucket* slot=empty; 76 while(slot !is null){ 77 i++; 78 slot=slot.next; 79 } 80 return i; 81 } 82 uint usedSlots()shared { 83 return bucketsNum-freeSlots; 84 } 85 } 86 alias BucketArraysType=Vector!(shared BucketsArray*); 87 88 //shared BucketsArray*[] bucketArrays; 89 BucketArraysType bucketArrays; 90 91 92 this(){ 93 //bucketArrays=Mallocator.instance.make!(BucketArraysType); 94 bucketArrays.extend(128); 95 } 96 ~this(){ 97 } 98 void[] oldData; 99 void extend(){ 100 //shared BucketsArray* arr=new shared BucketsArray; 101 shared BucketsArray* arr=cast(shared BucketsArray*)Mallocator.instance.make!(BucketsArray); 102 (*arr).initialize(); 103 if(!bucketArrays.canAddWithoutRealloc){ 104 if(oldData !is null){ 105 bucketArrays.freeData(oldData);//free on next alloc, noone should use the old array 106 } 107 oldData=bucketArrays.manualExtend(); 108 } 109 bucketArrays~=arr; 110 } 111 T* make(T,Args...)(auto ref Args args){ 112 void[] memory=allocate(); 113 //TODO some checks: aligment, size, itp?? 114 return memory.emplace!(T)( args ); 115 } 116 void[] allocate(){ 117 FF:foreach(i,bucketsArray;bucketArrays){ 118 if(bucketsArray.empty is null)continue; 119 120 shared Bucket* emptyBucket; 121 do{ 122 BACK: 123 emptyBucket=atomicLoad(bucketsArray.empty); 124 if(emptyBucket is null){ 125 continue FF; 126 } 127 if(emptyBucket==invalidValue){ 128 goto BACK; 129 } 130 }while(!cas(&bucketsArray.empty,emptyBucket,invalidValue)); 131 atomicStore(bucketsArray.empty,emptyBucket.next); 132 return cast(void[])emptyBucket.data; 133 } 134 135 //assert(0); 136 synchronized(this){ 137 extend(); 138 auto bucketsArray=bucketArrays[$-1]; 139 shared Bucket* empty=bucketsArray.empty; 140 bucketsArray.empty=(*bucketsArray.empty).next; 141 return cast(void[])empty.data; 142 } 143 144 } 145 void dispose(T)(T* obj){ 146 deallocate(cast(void[])obj[0..1]); 147 } 148 void deallocate(void[] data){ 149 foreach(bucketsArray;bucketArrays){ 150 auto ptr=bucketsArray.buckets.ptr; 151 auto dptr=data.ptr; 152 if(dptr>=ptr+bucketsNum || dptr<ptr){ 153 continue; 154 } 155 shared Bucket* bucket=cast(shared Bucket*)data.ptr; 156 shared Bucket* emptyBucket; 157 158 do{ 159 BACK: 160 emptyBucket=atomicLoad(bucketsArray.empty); 161 if(emptyBucket==invalidValue){ 162 goto BACK; 163 } 164 bucket.next=emptyBucket; 165 }while(!cas(&bucketsArray.empty,emptyBucket,bucket)); 166 return; 167 } 168 writelnng(data.ptr); 169 assert(0); 170 } 171 172 uint usedSlots(){ 173 uint sum; 174 foreach(bucketsArray;bucketArrays)sum+=bucketsArray.usedSlots; 175 return sum; 176 177 } 178 } 179 180 181 182 void ttt(){ 183 BucketAllocator!(64) allocator=Mallocator.instance.make!(BucketAllocator!64); 184 scope(exit)Mallocator.instance.dispose(allocator); 185 foreach(k;0..123){ 186 void[][] memories; 187 assert(allocator.bucketArrays[0].freeSlots==allocator.bucketsNum); 188 foreach(i;0..allocator.bucketsNum){ 189 memories~=allocator.allocate(); 190 } 191 assert(allocator.bucketArrays[0].freeSlots==0); 192 foreach(i;0..allocator.bucketsNum){ 193 memories~=allocator.allocate(); 194 assert(allocator.bucketArrays.length==2); 195 } 196 foreach(i,m;memories){ 197 allocator.deallocate(m); 198 } 199 } 200 201 } 202 import mutils.benchmark; 203 void testAL(){ 204 BucketAllocator!(64) allocator=Mallocator.instance.make!(BucketAllocator!(64)); 205 scope(exit)Mallocator.instance.dispose(allocator); 206 shared ulong sum; 207 void test(){ 208 foreach(k;0..1000){ 209 int*[] memories; 210 uint rand=uniform(130,140); 211 memories=Mallocator.instance.makeArray!(int*)(rand); 212 scope(exit)Mallocator.instance.dispose(memories); 213 foreach(i;0..rand){ 214 memories[i]=allocator.make!int(); 215 } 216 foreach(m;memories){ 217 allocator.dispose(m); 218 } 219 atomicOp!"+="(sum,memories.length); 220 } 221 } 222 void testAdd(){ 223 foreach(i;0..128){ 224 allocator.allocate(); 225 } 226 } 227 foreach(i;0..10000){ 228 sum=0; 229 StopWatch sw; 230 sw.start(); 231 testMultithreaded(&test,16); 232 sw.stop(); 233 writefln( "Benchmark: %s %s[ms], %s[it/ms]",sum,sw.msecs,sum/sw.msecs); 234 235 assert(allocator.usedSlots==0); 236 } 237 238 } 239 unittest{ 240 //testAL(); 241 }