Changeset 295dd61 for libcfa/src
- Timestamp:
- Dec 6, 2021, 5:06:14 PM (4 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
- Children:
- 75873cf
- Parents:
- 813dfd86 (diff), a83012bf (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- libcfa/src
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
r813dfd86 r295dd61 84 84 time.hfa \ 85 85 bits/weakso_locks.hfa \ 86 algorithms/range_iterator.hfa \ 86 87 containers/maybe.hfa \ 87 88 containers/pair.hfa \ -
libcfa/src/concurrency/io.cfa
r813dfd86 r295dd61 33 33 #include <sys/syscall.h> 34 34 #include <sys/eventfd.h> 35 #include <sys/uio.h> 35 36 36 37 #include <linux/io_uring.h> … … 133 134 } 134 135 135 void __cfa_io_flush( processor * proc) {136 bool __cfa_io_flush( processor * proc, int min_comp ) { 136 137 /* paranoid */ verify( ! __preemption_enabled() ); 137 138 /* paranoid */ verify( proc ); … … 141 142 $io_context & ctx = *proc->io.ctx; 142 143 143 // for(i; 2) {144 // unsigned idx = proc->rdq.id + i;145 // cltr->ready_queue.lanes.tscs[idx].tv = -1ull;146 // }147 148 144 __ioarbiter_flush( ctx ); 149 145 150 146 __STATS__( true, io.calls.flush++; ) 151 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0,0, (sigset_t *)0p, _NSIG / 8);147 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, min_comp, min_comp > 0 ? IORING_ENTER_GETEVENTS : 0, (sigset_t *)0p, _NSIG / 8); 152 148 if( ret < 0 ) { 153 149 switch((int)errno) { … … 157 153 // Update statistics 158 154 __STATS__( false, io.calls.errors.busy ++; ) 159 // for(i; 2) { 160 // unsigned idx = proc->rdq.id + i; 161 // cltr->ready_queue.lanes.tscs[idx].tv = rdtscl(); 162 // } 163 return; 155 return false; 164 156 default: 165 157 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); … … 182 174 183 175 ctx.proc->io.pending = false; 184 185 __cfa_io_drain( proc ); 186 // for(i; 2) { 187 // unsigned idx = proc->rdq.id + i; 188 // cltr->ready_queue.lanes.tscs[idx].tv = rdtscl(); 189 // } 176 ready_schedule_lock(); 177 bool ret = __cfa_io_drain( proc ); 178 ready_schedule_unlock(); 179 return ret; 190 180 } 191 181 … … 291 281 } 292 282 293 294 283 //============================================================================================= 295 284 // submission … … 314 303 ctx->proc->io.dirty = true; 315 304 if(sq.to_submit > 30 || !lazy) { 316 ready_schedule_lock(); 317 __cfa_io_flush( ctx->proc ); 318 ready_schedule_unlock(); 305 __cfa_io_flush( ctx->proc, 0 ); 319 306 } 320 307 } … … 515 502 } 516 503 } 504 505 #if defined(CFA_WITH_IO_URING_IDLE) 506 bool __kernel_read(processor * proc, io_future_t & future, iovec & iov, int fd) { 507 $io_context * ctx = proc->io.ctx; 508 /* paranoid */ verify( ! __preemption_enabled() ); 509 /* paranoid */ verify( proc == __cfaabi_tls.this_processor ); 510 /* paranoid */ verify( ctx ); 511 512 __u32 idx; 513 struct io_uring_sqe * sqe; 514 515 // We can proceed to the fast path 516 if( !__alloc(ctx, &idx, 1) ) return false; 517 518 // Allocation was successful 519 __fill( &sqe, 1, &idx, ctx ); 520 521 sqe->user_data = (uintptr_t)&future; 522 sqe->flags = 0; 523 sqe->fd = fd; 524 sqe->off = 0; 525 sqe->ioprio = 0; 526 sqe->fsync_flags = 0; 527 sqe->__pad2[0] = 0; 528 sqe->__pad2[1] = 0; 529 sqe->__pad2[2] = 0; 530 531 #if defined(CFA_HAVE_IORING_OP_READ) 532 sqe->opcode = IORING_OP_READ; 533 sqe->addr = (uint64_t)iov.iov_base; 534 sqe->len = iov.iov_len; 535 #elif defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV) 536 sqe->opcode = IORING_OP_READV; 537 sqe->addr = (uintptr_t)&iov; 538 sqe->len = 1; 539 #else 540 #error CFA_WITH_IO_URING_IDLE but none of CFA_HAVE_READV, CFA_HAVE_IORING_OP_READV or CFA_HAVE_IORING_OP_READ defined 541 #endif 542 543 asm volatile("": : :"memory"); 544 545 /* paranoid */ verify( sqe->user_data == (uintptr_t)&future ); 546 __submit( ctx, &idx, 1, true ); 547 548 /* paranoid */ verify( proc == __cfaabi_tls.this_processor ); 549 /* paranoid */ verify( ! __preemption_enabled() ); 550 } 551 #endif 517 552 #endif -
libcfa/src/concurrency/io/setup.cfa
r813dfd86 r295dd61 32 32 33 33 void __cfa_io_start( processor * proc ) {} 34 void __cfa_io_flush( processor * proc) {}34 bool __cfa_io_flush( processor * proc, int ) {} 35 35 void __cfa_io_stop ( processor * proc ) {} 36 36 … … 111 111 this.ext_sq.empty = true; 112 112 (this.ext_sq.queue){}; 113 __io_uring_setup( this, cl.io.params, proc->idle );113 __io_uring_setup( this, cl.io.params, proc->idle_fd ); 114 114 __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this); 115 115 } … … 220 220 cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes); 221 221 222 // Step 4 : eventfd 223 // io_uring_register is so f*cking slow on some machine that it 224 // will never succeed if preemption isn't hard blocked 225 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd); 226 227 __disable_interrupts_hard(); 228 229 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 230 if (ret < 0) { 231 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); 232 } 233 234 __enable_interrupts_hard(); 235 236 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd); 222 #if !defined(CFA_WITH_IO_URING_IDLE) 223 // Step 4 : eventfd 224 // io_uring_register is so f*cking slow on some machine that it 225 // will never succeed if preemption isn't hard blocked 226 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd); 227 228 __disable_interrupts_hard(); 229 230 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 231 if (ret < 0) { 232 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); 233 } 234 235 __enable_interrupts_hard(); 236 237 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd); 238 #endif 237 239 238 240 // some paranoid checks -
libcfa/src/concurrency/io/types.hfa
r813dfd86 r295dd61 185 185 186 186 // Wait for the future to be fulfilled 187 bool wait( io_future_t & this ) { 188 return wait(this.self); 189 } 190 191 void reset( io_future_t & this ) { 192 return reset(this.self); 193 } 187 bool wait ( io_future_t & this ) { return wait (this.self); } 188 void reset ( io_future_t & this ) { return reset (this.self); } 189 bool available( io_future_t & this ) { return available(this.self); } 194 190 } -
libcfa/src/concurrency/kernel.cfa
r813dfd86 r295dd61 27 27 extern "C" { 28 28 #include <sys/eventfd.h> 29 #include <sys/uio.h> 29 30 } 30 31 … … 34 35 #include "strstream.hfa" 35 36 #include "device/cpu.hfa" 37 #include "io/types.hfa" 36 38 37 39 //Private includes … … 124 126 static void __wake_one(cluster * cltr); 125 127 128 static void idle_sleep(processor * proc, io_future_t & future, iovec & iov); 126 129 static bool mark_idle (__cluster_proc_list & idles, processor & proc); 127 130 static void mark_awake(__cluster_proc_list & idles, processor & proc); … … 129 132 extern void __cfa_io_start( processor * ); 130 133 extern bool __cfa_io_drain( processor * ); 131 extern void __cfa_io_flush( processor *);134 extern bool __cfa_io_flush( processor *, int min_comp ); 132 135 extern void __cfa_io_stop ( processor * ); 133 136 static inline bool __maybe_io_drain( processor * ); 137 138 #if defined(CFA_WITH_IO_URING_IDLE) 139 extern bool __kernel_read(processor * proc, io_future_t & future, iovec &, int fd); 140 #endif 134 141 135 142 extern void __disable_interrupts_hard(); … … 147 154 /* paranoid */ verify( __preemption_enabled() ); 148 155 } 156 149 157 150 158 //============================================================================================= … … 162 170 verify(this); 163 171 172 io_future_t future; // used for idle sleep when io_uring is present 173 future.self.ptr = 1p; // mark it as already fulfilled so we know if there is a pending request or not 174 eventfd_t idle_val; 175 iovec idle_iovec = { &idle_val, sizeof(idle_val) }; 176 164 177 __cfa_io_start( this ); 165 178 … … 195 208 196 209 if( !readyThread ) { 197 ready_schedule_lock(); 198 __cfa_io_flush( this ); 199 ready_schedule_unlock(); 210 __cfa_io_flush( this, 0 ); 200 211 201 212 readyThread = __next_thread_slow( this->cltr ); … … 228 239 } 229 240 230 #if !defined(__CFA_NO_STATISTICS__) 231 if(this->print_halts) { 232 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 241 idle_sleep( this, future, idle_iovec ); 242 243 // We were woken up, remove self from idle 244 mark_awake(this->cltr->procs, * this); 245 246 // DON'T just proceed, start looking again 247 continue MAIN_LOOP; 248 } 249 250 /* paranoid */ verify( readyThread ); 251 252 // Reset io dirty bit 253 this->io.dirty = false; 254 255 // We found a thread run it 256 __run_thread(this, readyThread); 257 258 // Are we done? 259 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 260 261 if(this->io.pending && !this->io.dirty) { 262 __cfa_io_flush( this, 0 ); 263 } 264 265 #else 266 #warning new kernel loop 267 SEARCH: { 268 /* paranoid */ verify( ! __preemption_enabled() ); 269 270 // First, lock the scheduler since we are searching for a thread 271 ready_schedule_lock(); 272 273 // Try to get the next thread 274 readyThread = pop_fast( this->cltr ); 275 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 276 277 // If we can't find a thread, might as well flush any outstanding I/O 278 if(this->io.pending) { __cfa_io_flush( this, 0 ); } 279 280 // Spin a little on I/O, just in case 281 for(5) { 282 __maybe_io_drain( this ); 283 readyThread = pop_fast( this->cltr ); 284 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 285 } 286 287 // no luck, try stealing a few times 288 for(5) { 289 if( __maybe_io_drain( this ) ) { 290 readyThread = pop_fast( this->cltr ); 291 } else { 292 readyThread = pop_slow( this->cltr ); 233 293 } 234 #endif 235 236 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 294 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 295 } 296 297 // still no luck, search for a thread 298 readyThread = pop_search( this->cltr ); 299 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 300 301 // Don't block if we are done 302 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) { 303 ready_schedule_unlock(); 304 break MAIN_LOOP; 305 } 306 307 __STATS( __tls_stats()->ready.sleep.halts++; ) 308 309 // Push self to idle stack 310 ready_schedule_unlock(); 311 if(!mark_idle(this->cltr->procs, * this)) goto SEARCH; 312 ready_schedule_lock(); 313 314 // Confirm the ready-queue is empty 315 __maybe_io_drain( this ); 316 readyThread = pop_search( this->cltr ); 317 ready_schedule_unlock(); 318 319 if( readyThread ) { 320 // A thread was found, cancel the halt 321 mark_awake(this->cltr->procs, * this); 322 323 __STATS( __tls_stats()->ready.sleep.cancels++; ) 324 325 // continue the main loop 326 break SEARCH; 327 } 328 329 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 330 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 237 331 238 332 { 239 333 eventfd_t val; 240 ssize_t ret = read( this->idle , &val, sizeof(val) );334 ssize_t ret = read( this->idle_fd, &val, sizeof(val) ); 241 335 if(ret < 0) { 242 336 switch((int)errno) { … … 254 348 } 255 349 256 #if !defined(__CFA_NO_STATISTICS__) 257 if(this->print_halts) { 258 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 259 } 260 #endif 350 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) 261 351 262 352 // We were woken up, remove self from idle … … 267 357 } 268 358 269 /* paranoid */ verify( readyThread );270 271 // Reset io dirty bit272 this->io.dirty = false;273 274 // We found a thread run it275 __run_thread(this, readyThread);276 277 // Are we done?278 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;279 280 if(this->io.pending && !this->io.dirty) {281 ready_schedule_lock();282 __cfa_io_flush( this );283 ready_schedule_unlock();284 }285 286 #else287 #warning new kernel loop288 SEARCH: {289 /* paranoid */ verify( ! __preemption_enabled() );290 291 // First, lock the scheduler since we are searching for a thread292 ready_schedule_lock();293 294 // Try to get the next thread295 readyThread = pop_fast( this->cltr );296 if(readyThread) { ready_schedule_unlock(); break SEARCH; }297 298 // If we can't find a thread, might as well flush any outstanding I/O299 if(this->io.pending) { __cfa_io_flush( this ); }300 301 // Spin a little on I/O, just in case302 for(5) {303 __maybe_io_drain( this );304 readyThread = pop_fast( this->cltr );305 if(readyThread) { ready_schedule_unlock(); break SEARCH; }306 }307 308 // no luck, try stealing a few times309 for(5) {310 if( __maybe_io_drain( this ) ) {311 readyThread = pop_fast( this->cltr );312 } else {313 readyThread = pop_slow( this->cltr );314 }315 if(readyThread) { ready_schedule_unlock(); break SEARCH; }316 }317 318 // still no luck, search for a thread319 readyThread = pop_search( this->cltr );320 if(readyThread) { ready_schedule_unlock(); break SEARCH; }321 322 // Don't block if we are done323 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {324 ready_schedule_unlock();325 break MAIN_LOOP;326 }327 328 __STATS( __tls_stats()->ready.sleep.halts++; )329 330 // Push self to idle stack331 ready_schedule_unlock();332 if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;333 ready_schedule_lock();334 335 // Confirm the ready-queue is empty336 __maybe_io_drain( this );337 readyThread = pop_search( this->cltr );338 ready_schedule_unlock();339 340 if( readyThread ) {341 // A thread was found, cancel the halt342 mark_awake(this->cltr->procs, * this);343 344 __STATS( __tls_stats()->ready.sleep.cancels++; )345 346 // continue the main loop347 break SEARCH;348 }349 350 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )351 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);352 353 {354 eventfd_t val;355 ssize_t ret = read( this->idle, &val, sizeof(val) );356 if(ret < 0) {357 switch((int)errno) {358 case EAGAIN:359 #if EAGAIN != EWOULDBLOCK360 case EWOULDBLOCK:361 #endif362 case EINTR:363 // No need to do anything special here, just assume it's a legitimate wake-up364 break;365 default:366 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );367 }368 }369 }370 371 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )372 373 // We were woken up, remove self from idle374 mark_awake(this->cltr->procs, * this);375 376 // DON'T just proceed, start looking again377 continue MAIN_LOOP;378 }379 380 359 RUN_THREAD: 381 360 /* paranoid */ verify( ! __preemption_enabled() ); … … 392 371 393 372 if(this->io.pending && !this->io.dirty) { 394 __cfa_io_flush( this );373 __cfa_io_flush( this, 0 ); 395 374 } 396 375 … … 402 381 403 382 __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this); 383 } 384 385 for(int i = 0; !available(future); i++) { 386 if(i > 1000) __cfaabi_dbg_write( "ERROR: kernel has bin spinning on a flush after exit loop.\n", 60); 387 __cfa_io_flush( this, 1 ); 404 388 } 405 389 … … 798 782 eventfd_t val; 799 783 val = 1; 800 eventfd_write( this->idle , val );784 eventfd_write( this->idle_fd, val ); 801 785 __enable_interrupts_checked(); 786 } 787 788 static void idle_sleep(processor * this, io_future_t & future, iovec & iov) { 789 #if !defined(CFA_WITH_IO_URING_IDLE) 790 #if !defined(__CFA_NO_STATISTICS__) 791 if(this->print_halts) { 792 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 793 } 794 #endif 795 796 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 797 798 { 799 eventfd_t val; 800 ssize_t ret = read( this->idle_fd, &val, sizeof(val) ); 801 if(ret < 0) { 802 switch((int)errno) { 803 case EAGAIN: 804 #if EAGAIN != EWOULDBLOCK 805 case EWOULDBLOCK: 806 #endif 807 case EINTR: 808 // No need to do anything special here, just assume it's a legitimate wake-up 809 break; 810 default: 811 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 812 } 813 } 814 } 815 816 #if !defined(__CFA_NO_STATISTICS__) 817 if(this->print_halts) { 818 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 819 } 820 #endif 821 #else 822 // Do we already have a pending read 823 if(available(future)) { 824 // There is no pending read, we need to add one 825 reset(future); 826 827 __kernel_read(this, future, iov, this->idle_fd ); 828 } 829 830 __cfa_io_flush( this, 1 ); 831 #endif 802 832 } 803 833 … … 810 840 insert_first(this.idles, proc); 811 841 812 __atomic_store_n(&this.fd, proc.idle , __ATOMIC_SEQ_CST);842 __atomic_store_n(&this.fd, proc.idle_fd, __ATOMIC_SEQ_CST); 813 843 unlock( this ); 814 844 /* paranoid */ verify( ! __preemption_enabled() ); … … 827 857 { 828 858 int fd = 0; 829 if(!this.idles`isEmpty) fd = this.idles`first.idle ;859 if(!this.idles`isEmpty) fd = this.idles`first.idle_fd; 830 860 __atomic_store_n(&this.fd, fd, __ATOMIC_SEQ_CST); 831 861 } -
libcfa/src/concurrency/kernel.hfa
r813dfd86 r295dd61 100 100 101 101 // Idle lock (kernel semaphore) 102 int idle ;102 int idle_fd; 103 103 104 104 // Termination synchronisation (user semaphore) -
libcfa/src/concurrency/kernel/startup.cfa
r813dfd86 r295dd61 527 527 this.local_data = 0p; 528 528 529 this.idle = eventfd(0, 0);530 if (idle < 0) {529 this.idle_fd = eventfd(0, 0); 530 if (idle_fd < 0) { 531 531 abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno)); 532 532 } … … 542 542 // Not a ctor, it just preps the destruction but should not destroy members 543 543 static void deinit(processor & this) { 544 close(this.idle );544 close(this.idle_fd); 545 545 } 546 546 -
libcfa/src/concurrency/kernel_private.hfa
r813dfd86 r295dd61 39 39 } 40 40 41 // Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call 42 #define CFA_WANT_IO_URING_IDLE 43 44 // Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call 45 #if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H) 46 #if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV)) 47 #define CFA_WITH_IO_URING_IDLE 48 #endif 49 #endif 50 41 51 //----------------------------------------------------------------------------- 42 52 // Scheduler … … 149 159 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 150 160 } 151 152 153 154 155 161 156 162 //----------------------------------------------------------------------- -
libcfa/src/device/cpu.cfa
r813dfd86 r295dd61 135 135 count++; 136 136 } 137 iterate_dir(path, lambda); 137 int ret = iterate_dir(path, lambda); 138 if(ret == ENOTDIR) return 0; 138 139 139 140 /* paranoid */ verifyf(count == max + 1, "Inconsistent %s count, counted %d, but max %s was %d", prefix, count, prefix, (int)max); … … 159 160 160 161 const char * _; 161 int cnt = read_width(buff, r - 1, &_); 162 /* paranoid */ verify(cnt == count_prefix_dirs("/sys/devices/system/cpu", "cpu")); 163 return cnt; 162 return read_width(buff, r - 1, &_);; 164 163 } 165 164 … … 226 225 227 226 struct raw_cache_instance { 228 idx_range_t range; 229 unsigned width; 230 unsigned char level; 227 idx_range_t range; // A text description of the cpus covered 228 unsigned width; // The number of cpus covered 229 unsigned char level; // the cache level 231 230 // FIXME add at least size and type 232 231 }; … … 235 234 static void ^?{}(raw_cache_instance & this) { free(this.range);} 236 235 236 // Returns a 2D array of instances of size [cpu count][cache levels] 237 // where cache level doesn't include instruction caches 237 238 raw_cache_instance ** build_raw_cache_table(unsigned cpus, unsigned idxs, unsigned cache_levels) 238 239 { 239 240 raw_cache_instance ** raw = alloc(cpus); 241 242 // TODO: this loop is broken, it only works if the present cpu start at 0 and are contiguous which is not guaranteed. 240 243 for(i; cpus) { 241 raw[i] = alloc(cache_levels); 242 void addcache(unsigned fidx, unsigned char level, idx_range_t range, size_t len) { 243 /* paranoid */ verifyf(level <= cache_levels, "Unexpected cache level %d on cpu %u index %u", (int)level, i, fidx); 244 245 unsigned idx = cache_levels - level; 246 raw_cache_instance & r = raw[i][idx]; 247 r.range = strndup(range, len); 248 r.level = level; 249 const char * end; 250 r.width = read_width(range, len, &end); 251 } 252 foreach_cacheidx(i, idxs, addcache); 244 if (cache_levels > 0) { 245 raw[i] = alloc(cache_levels); 246 void addcache(unsigned fidx, unsigned char level, idx_range_t range, size_t len) { 247 /* paranoid */ verifyf(level <= cache_levels, "Unexpected cache level %d on cpu %u index %u", (int)level, i, fidx); 248 249 unsigned idx = cache_levels - level; 250 raw_cache_instance & r = raw[i][idx]; 251 r.range = strndup(range, len); 252 r.level = level; 253 const char * end; 254 r.width = read_width(range, len, &end); 255 } 256 foreach_cacheidx(i, idxs, addcache); 257 } 258 else { 259 char buf[128]; 260 snprintf(buf, 128, "0-%u", cpus); 261 raw[i] = alloc(); 262 raw[i]->range = strndup(buf, 128); 263 raw[i]->level = 0; 264 raw[i]->width = cpus; 265 } 253 266 } 254 267 … … 333 346 unsigned cache_levels = 0; 334 347 unsigned llc = 0; 335 {348 if (idxs != 0) { 336 349 unsigned char prev = -1u; 337 350 void first(unsigned idx, unsigned char level, const char * map, size_t len) { … … 416 429 cpu_info.llc_map = entries; 417 430 cpu_info.hthrd_count = cpus; 431 cpu_info.llc_count = map_cnt; 418 432 } 419 433 -
libcfa/src/device/cpu.hfa
r813dfd86 r295dd61 23 23 24 24 struct cpu_info_t { 25 // array of size [hthrd_count]25 // Array of size [hthrd_count] 26 26 const cpu_map_entry_t * llc_map; 27 27 28 28 // Number of _hardware_ threads present in the system 29 29 size_t hthrd_count; 30 31 // Number of distinct last level caches 32 size_t llc_count; 30 33 }; 31 34
Note:
See TracChangeset
for help on using the changeset viewer.