Changes in / [f93c50a:7e7a076]
- Files:
-
- 8 deleted
- 24 edited
-
doc/theses/andrew_beach_MMath/Makefile (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/existing.tex (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/features.tex (modified) (4 diffs)
-
doc/theses/andrew_beach_MMath/implement.tex (modified) (4 diffs)
-
doc/theses/andrew_beach_MMath/intro.tex (modified) (8 diffs)
-
doc/theses/andrew_beach_MMath/performance.tex (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/resumhandle.fig (deleted)
-
doc/theses/andrew_beach_MMath/termhandle.fig (deleted)
-
doc/theses/andrew_beach_MMath/uw-ethesis.bib (modified) (1 diff)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (9 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (2 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (10 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/ready_queue.cfa (modified) (15 diffs)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/stats.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/stats.hfa (modified) (1 diff)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/containers/string_res.cfa (modified) (8 diffs)
-
libcfa/src/containers/string_res.hfa (modified) (1 diff)
-
libcfa/src/fstream.cfa (modified) (15 diffs)
-
tests/collections/.expect/string-gc.txt (deleted)
-
tests/collections/.expect/string-overwrite.txt (deleted)
-
tests/collections/string-gc.cfa (deleted)
-
tests/collections/string-overwrite.cfa (deleted)
-
tools/perf/png.py (deleted)
-
tools/perf/process_stat_array.py (modified) (5 diffs)
-
tools/perf/sample.py (deleted)
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/Makefile
rf93c50a r7e7a076 31 31 32 32 # The main rule, it does all the tex/latex processing. 33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} termhandle.pstex resumhandle.pstexMakefile | ${BUILD}33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD} 34 34 ${LATEX} ${BASE} 35 35 ${BIBTEX} ${BUILD}/${BASE} … … 40 40 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD} 41 41 fig2dev -L eepic $< > $@ 42 43 %.pstex : %.fig | ${Build}44 fig2dev -L pstex $< > ${BUILD}/$@45 fig2dev -L pstex_t -p ${BUILD}/$@ $< > ${BUILD}/$@_t46 42 47 43 # Step through dvi & postscript to handle xfig specials. -
doc/theses/andrew_beach_MMath/existing.tex
rf93c50a r7e7a076 49 49 asterisk (@*@) is replaced with a ampersand (@&@); 50 50 this includes cv-qualifiers (\snake{const} and \snake{volatile}) 51 %\todo{Should I go into even more detail on cv-qualifiers.} 51 52 and multiple levels of reference. 52 53 -
doc/theses/andrew_beach_MMath/features.tex
rf93c50a r7e7a076 129 129 \section{Virtuals} 130 130 \label{s:virtuals} 131 A common feature in many programming languages is a tool to pair code 132 (behaviour) with data. 133 In \CFA this is done with the virtual system, 134 which allow type information to be abstracted away, recovered and allow 135 operations to be performed on the abstract objects. 136 131 %\todo{Maybe explain what "virtual" actually means.} 137 132 Virtual types and casts are not part of \CFA's EHM nor are they required for 138 133 an EHM. … … 493 488 Since it is so general, a more specific handler can be defined, 494 489 overriding the default behaviour for the specific exception types. 495 496 For example, consider an error reading a configuration file. 497 This is most likely a problem with the configuration file (@config_error@), 498 but the function could have been passed the wrong file name (@arg_error@). 499 In this case the function could raise one exception and then, if it is 500 unhandled, raise the other. 501 This is not usual behaviour for either exception so changing the 502 default handler will be done locally: 503 \begin{cfa} 504 { 505 void defaultTerminationHandler(config_error &) { 506 throw (arg_error){arg_vt}; 507 } 508 throw (config_error){config_vt}; 509 } 510 \end{cfa} 490 %\todo{Examples?} 511 491 512 492 \subsection{Resumption} … … 571 551 the just handled exception came from, and continues executing after it, 572 552 not after the try statement. 573 574 For instance, a resumption used to send messages to the logger may not 575 need to be handled at all. Putting the following default handler 576 at the global scope can make handling that exception optional by default. 577 \begin{cfa} 578 void defaultResumptionHandler(log_message &) { 579 // Nothing, it is fine not to handle logging. 580 } 581 // ... No change at raise sites. ... 582 throwResume (log_message){strlit_log, "Begin event processing."} 583 \end{cfa} 553 %\todo{Examples?} 584 554 585 555 \subsubsection{Resumption Marking} … … 908 878 After a coroutine stack is unwound, control returns to the @resume@ function 909 879 that most recently resumed it. @resume@ reports a 910 @CoroutineCancelled@ exception, which contains a reference to the cancelled880 @CoroutineCancelled@ exception, which contains a references to the cancelled 911 881 coroutine and the exception used to cancel it. 912 882 The @resume@ function also takes the \defaultResumptionHandler{} from the -
doc/theses/andrew_beach_MMath/implement.tex
rf93c50a r7e7a076 50 50 The problem is that a type ID may appear in multiple TUs that compose a 51 51 program (see \autoref{ss:VirtualTable}), so the initial solution would seem 52 to be make it external in each translation unit. Ho wever, the type ID must52 to be make it external in each translation unit. Hovever, the type ID must 53 53 have a declaration in (exactly) one of the TUs to create the storage. 54 54 No other declaration related to the virtual type has this property, so doing … … 167 167 \subsection{Virtual Table} 168 168 \label{ss:VirtualTable} 169 %\todo{Clarify virtual table type vs. virtual table instance.} 169 170 Each virtual type has a virtual table type that stores its type ID and 170 171 virtual members. 171 An instance of a virtual type is bound to a virtual table instance, 172 which have the values of the virtual members. 173 Both the layout of the fields (in the virtual table type) 174 and their value (in the virtual table instance) are decided by the rules given 172 Each virtual type instance is bound to a table instance that is filled with 173 the values of virtual members. 174 Both the layout of the fields and their value are decided by the rules given 175 175 below. 176 176 … … 414 414 of a function's state with @setjmp@ and restoring that snapshot with 415 415 @longjmp@. This approach bypasses the need to know stack details by simply 416 reset ting to a snapshot of an arbitrary but existing function frame on the416 reseting to a snapshot of an arbitrary but existing function frame on the 417 417 stack. It is up to the programmer to ensure the snapshot is valid when it is 418 418 reset and that all required cleanup from the unwound stacks is performed. 419 Because it does not automate or check any of this cleanup, 420 it can be easy to make mistakes and always must be handled manually. 419 This approach is fragile and requires extra work in the surrounding code. 421 420 422 421 With respect to the extra work in the surrounding code, … … 436 435 library that provides tools for stack walking, handler execution, and 437 436 unwinding. What follows is an overview of all the relevant features of 438 libunwind needed for this work. 439 Following that is the description of the \CFA code that uses libunwind 440 to implement termination. 437 libunwind needed for this work, and how \CFA uses them to implement exception 438 handling. 441 439 442 440 \subsection{libunwind Usage} -
doc/theses/andrew_beach_MMath/intro.tex
rf93c50a r7e7a076 39 39 it returns control to that function. 40 40 \begin{center} 41 %\input{termination} 42 % 43 %\medskip 44 \input{termhandle.pstex_t} 45 % I hate these diagrams, but I can't access xfig to fix them and they are 46 % better than the alternative. 41 \input{termination} 47 42 \end{center} 43 %\todo{What does the right half of termination.fig mean?} 48 44 49 45 Resumption exception handling searches the stack for a handler and then calls … … 54 50 that preformed the raise, usually starting after the raise. 55 51 \begin{center} 56 %\input{resumption} 57 % 58 %\medskip 59 \input{resumhandle.pstex_t} 60 % The other one. 52 \input{resumption} 61 53 \end{center} 62 54 … … 222 214 unwinding the stack like in termination exception 223 215 handling.\cite{RustPanicMacro}\cite{RustPanicModule} 224 Go's panic th ough is very similar to a termination, except it only supports216 Go's panic through is very similar to a termination, except it only supports 225 217 a catch-all by calling \code{Go}{recover()}, simplifying the interface at 226 218 the cost of flexibility.\cite{Go:2021} … … 245 237 through multiple functions before it is addressed. 246 238 247 Here is an example of the pattern in Bash, where commands can only ``return"248 numbers and most output is done through streams of text.249 \begin{lstlisting}[language=bash,escapechar={}]250 # Immediately after running a command:251 case $? in252 0)253 # Success254 ;;255 1)256 # Error Code 1257 ;;258 2|3)259 # Error Code 2 or Error Code 3260 ;;261 # Add more cases as needed.262 asac263 \end{lstlisting}264 265 239 \item\emph{Special Return with Global Store}: 266 240 Similar to the error codes pattern but the function itself only returns … … 272 246 273 247 This approach avoids the multiple results issue encountered with straight 274 error codes as only a single error value has to be returned, 275 but otherwise has the same disadvantages and more. 248 error codes but otherwise has the same disadvantages and more. 276 249 Every function that reads or writes to the global store must agree on all 277 250 possible errors and managing it becomes more complex with concurrency. 278 279 This example shows some of what has to be done to robustly handle a C280 standard library function that reports errors this way.281 \begin{lstlisting}[language=C]282 // Make sure to clear the store.283 errno = 0;284 // Now a library function can set the error.285 int handle = open(path_name, flags);286 if (-1 == handle) {287 switch (errno) {288 case ENAMETOOLONG:289 // path_name is a bad argument.290 break;291 case ENFILE:292 // A system resource has been exausted.293 break;294 // And many more...295 }296 }297 \end{lstlisting}298 % cite open man page?299 251 300 252 \item\emph{Return Union}: … … 307 259 This pattern is very popular in any functional or semi-functional language 308 260 with primitive support for tagged unions (or algebraic data types). 309 Return unions can also be expressed as monads (evaluation in a context) 310 and often are in languages with special syntax for monadic evaluation, 311 such as Haskell's \code{haskell}{do} blocks. 312 261 % We need listing Rust/rust to format code snippets from it. 262 % Rust's \code{rust}{Result<T, E>} 313 263 The main advantage is that an arbitrary object can be used to represent an 314 264 error, so it can include a lot more information than a simple error code. … … 316 266 execution, and if there aren't primitive tagged unions proper, usage can be 317 267 hard to enforce. 318 % We need listing Rust/rust to format code snippets from it.319 % Rust's \code{rust}{Result<T, E>}320 321 This is a simple example of examining the result of a failing function in322 Haskell, using its \code{haskell}{Either} type.323 Examining \code{haskell}{error} further would likely involve more matching,324 but the type of \code{haskell}{error} is user defined so there are no325 general cases.326 \begin{lstlisting}[language=haskell]327 case failingFunction argA argB of328 Right value -> -- Use the successful computed value.329 Left error -> -- Handle the produced error.330 \end{lstlisting}331 332 Return unions as monads will result in the same code, but can hide most333 of the work to propagate errors in simple cases. The code to actually handle334 the errors, or to interact with other monads (a common case in these335 languages) still has to be written by hand.336 337 If \code{haskell}{failingFunction} is implemented with two helpers that338 use the same error type, then it can be implemented with a \code{haskell}{do}339 block.340 \begin{lstlisting}[language=haskell]341 failingFunction x y = do342 z <- helperOne x343 helperTwo y z344 \end{lstlisting}345 268 346 269 \item\emph{Handler Functions}: … … 363 286 function calls, but cheaper (constant time) to call, 364 287 they are more suited to more frequent (less exceptional) situations. 365 Although, in \Cpp and other languages that do not have checked exceptions,366 they can actually be enforced by the type system be more reliable.367 368 This is a more local example in \Cpp, using a function to provide369 a default value for a mapping.370 \begin{lstlisting}[language=C++]371 ValueT Map::key_or_default(KeyT key, ValueT(*make_default)(KeyT)) {372 ValueT * value = find_value(key);373 if (nullptr != value) {374 return *value;375 } else {376 return make_default(key);377 }378 }379 \end{lstlisting}380 288 \end{itemize} 381 289 -
doc/theses/andrew_beach_MMath/performance.tex
rf93c50a r7e7a076 37 37 resumption exceptions. Even the older programming languages with resumption 38 38 seem to be notable only for having resumption. 39 On the other hand, the functional equivalents to resumption are too new.40 There does not seem to be any standard implementations in well-known41 languages, so far they seem confined to extensions and research languages.42 % There was some maybe interesting comparison to an OCaml extension43 % but I'm not sure how to get that working if it is interesting.44 39 Instead, resumption is compared to its simulation in other programming 45 40 languages: fixup functions that are explicitly passed into a function. … … 317 312 \CFA, \Cpp and Java. 318 313 % To be exact, the Match All and Match None cases. 319 The most likely explination is that, 320 the generally faster languages have made ``common cases fast" at the expense 321 of the rarer cases. Since exceptions are considered rare, they are made 322 expensive to help speed up common actions, such as entering and leaving try 323 statements. 324 Python on the other hand, while generally slower than the other languages, 325 uses exceptions more and has not scarified their performance. 314 %\todo{Not true in Python.} 315 The most likely explanation is that, since exceptions 316 are rarely considered to be the common case, the more optimized languages 317 make that case expensive to improve other cases. 326 318 In addition, languages with high-level representations have a much 327 319 easier time scanning the stack as there is less to decode. -
doc/theses/andrew_beach_MMath/uw-ethesis.bib
rf93c50a r7e7a076 50 50 author={The Rust Team}, 51 51 key={Rust Panic Macro}, 52 howpublished={\href{https://doc.rust-lang.org/std/ macro.panic.html}{https://\-doc.rust-lang.org/\-std/\-macro.panic.html}},52 howpublished={\href{https://doc.rust-lang.org/std/panic/index.html}{https://\-doc.rust-lang.org/\-std/\-panic/\-index.html}}, 53 53 addendum={Accessed 2021-08-31}, 54 54 } -
libcfa/src/concurrency/clib/cfathread.cfa
rf93c50a r7e7a076 13 13 // Update Count : 14 14 // 15 16 // #define EPOLL_FOR_SOCKETS17 15 18 16 #include "fstream.hfa" … … 25 23 #include "cfathread.h" 26 24 27 extern "C" {28 #include <string.h>29 #include <errno.h>30 }31 32 25 extern void ?{}(processor &, const char[], cluster &, thread$ *); 33 26 extern "C" { 34 27 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 35 extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);36 28 } 37 29 38 30 extern Time __kernel_get_time(); 39 extern unsigned register_proc_id( void );40 31 41 32 //================================================================================ 42 // Epoll support for sockets 43 44 #if defined(EPOLL_FOR_SOCKETS) 45 extern "C" { 46 #include <sys/epoll.h> 47 #include <sys/resource.h> 48 } 49 50 static pthread_t master_poller; 51 static int master_epollfd = 0; 52 static size_t poller_cnt = 0; 53 static int * poller_fds = 0p; 54 static struct leaf_poller * pollers = 0p; 55 56 struct __attribute__((aligned)) fd_info_t { 57 int pollid; 58 size_t rearms; 59 }; 60 rlim_t fd_limit = 0; 61 static fd_info_t * volatile * fd_map = 0p; 62 63 void * master_epoll( __attribute__((unused)) void * args ) { 64 unsigned id = register_proc_id(); 65 66 enum { MAX_EVENTS = 5 }; 67 struct epoll_event events[MAX_EVENTS]; 68 for() { 69 int ret = epoll_wait(master_epollfd, events, MAX_EVENTS, -1); 70 if ( ret < 0 ) { 71 abort | "Master epoll error: " | strerror(errno); 72 } 73 74 for(i; ret) { 75 thread$ * thrd = (thread$ *)events[i].data.u64; 76 unpark( thrd ); 77 } 78 } 79 80 return 0p; 81 } 82 83 static inline int epoll_rearm(int epollfd, int fd, uint32_t event) { 84 struct epoll_event eevent; 85 eevent.events = event | EPOLLET | EPOLLONESHOT; 86 eevent.data.u64 = (uint64_t)active_thread(); 87 88 if(0 != epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &eevent)) 89 { 90 if(errno == ENOENT) return -1; 91 abort | acquire | "epoll" | epollfd | "ctl rearm" | fd | "error: " | errno | strerror(errno); 92 } 93 94 park(); 95 return 0; 96 } 97 98 thread leaf_poller { 99 int epollfd; 100 }; 101 102 void ?{}(leaf_poller & this, int fd) { this.epollfd = fd; } 103 104 void main(leaf_poller & this) { 105 enum { MAX_EVENTS = 1024 }; 106 struct epoll_event events[MAX_EVENTS]; 107 const int max_retries = 5; 108 int retries = max_retries; 109 110 struct epoll_event event; 111 event.events = EPOLLIN | EPOLLET | EPOLLONESHOT; 112 event.data.u64 = (uint64_t)&(thread&)this; 113 114 if(0 != epoll_ctl(master_epollfd, EPOLL_CTL_ADD, this.epollfd, &event)) 115 { 116 abort | "master epoll ctl add leaf: " | errno | strerror(errno); 117 } 118 119 park(); 120 121 for() { 122 yield(); 123 int ret = epoll_wait(this.epollfd, events, MAX_EVENTS, 0); 124 if ( ret < 0 ) { 125 abort | "Leaf epoll error: " | errno | strerror(errno); 126 } 127 128 if(ret) { 129 for(i; ret) { 130 thread$ * thrd = (thread$ *)events[i].data.u64; 131 unpark( thrd, UNPARK_REMOTE ); 132 } 133 } 134 else if(0 >= --retries) { 135 epoll_rearm(master_epollfd, this.epollfd, EPOLLIN); 136 } 137 } 138 } 139 140 void setup_epoll( void ) __attribute__(( constructor )); 141 void setup_epoll( void ) { 142 if(master_epollfd) abort | "Master epoll already setup"; 143 144 master_epollfd = epoll_create1(0); 145 if(master_epollfd == -1) { 146 abort | "failed to create master epoll: " | errno | strerror(errno); 147 } 148 149 struct rlimit rlim; 150 if(int ret = getrlimit(RLIMIT_NOFILE, &rlim); 0 != ret) { 151 abort | "failed to get nofile limit: " | errno | strerror(errno); 152 } 153 154 fd_limit = rlim.rlim_cur; 155 fd_map = alloc(fd_limit); 156 for(i;fd_limit) { 157 fd_map[i] = 0p; 158 } 159 160 poller_cnt = 2; 161 poller_fds = alloc(poller_cnt); 162 pollers = alloc(poller_cnt); 163 for(i; poller_cnt) { 164 poller_fds[i] = epoll_create1(0); 165 if(poller_fds[i] == -1) { 166 abort | "failed to create leaf epoll [" | i | "]: " | errno | strerror(errno); 167 } 168 169 (pollers[i]){ poller_fds[i] }; 170 } 171 172 pthread_attr_t attr; 173 if (int ret = pthread_attr_init(&attr); 0 != ret) { 174 abort | "failed to create master epoll thread attr: " | ret | strerror(ret); 175 } 176 177 if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) { 178 abort | "failed to create master epoll thread: " | ret | strerror(ret); 179 } 180 } 181 182 static inline int epoll_wait(int fd, uint32_t event) { 183 if(fd_map[fd] >= 1p) { 184 fd_map[fd]->rearms++; 185 epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event); 186 return 0; 187 } 188 189 for() { 190 fd_info_t * expected = 0p; 191 fd_info_t * sentinel = 1p; 192 if(__atomic_compare_exchange_n( &(fd_map[fd]), &expected, sentinel, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED)) { 193 struct epoll_event eevent; 194 eevent.events = event | EPOLLET | EPOLLONESHOT; 195 eevent.data.u64 = (uint64_t)active_thread(); 196 197 int id = thread_rand() % poller_cnt; 198 if(0 != epoll_ctl(poller_fds[id], EPOLL_CTL_ADD, fd, &eevent)) 199 { 200 abort | "epoll ctl add" | poller_fds[id] | fd | fd_map[fd] | expected | "error: " | errno | strerror(errno); 201 } 202 203 fd_info_t * ninfo = alloc(); 204 ninfo->pollid = id; 205 ninfo->rearms = 0; 206 __atomic_store_n( &fd_map[fd], ninfo, __ATOMIC_SEQ_CST); 207 208 park(); 209 return 0; 210 } 211 212 if(expected >= 0) { 213 fd_map[fd]->rearms++; 214 epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event); 215 return 0; 216 } 217 218 Pause(); 219 } 220 } 221 #endif 222 223 //================================================================================ 224 // Thread run by the C Interface 33 // Thread run y the C Interface 225 34 226 35 struct cfathread_object { … … 436 245 // Mutex 437 246 struct cfathread_mutex { 438 linear_backoff_then_block_lock impl;247 fast_lock impl; 439 248 }; 440 249 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; } … … 451 260 // Condition 452 261 struct cfathread_condition { 453 condition_variable( linear_backoff_then_block_lock) impl;262 condition_variable(fast_lock) impl; 454 263 }; 455 264 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; } … … 479 288 // IO operations 480 289 int cfathread_socket(int domain, int type, int protocol) { 481 return socket(domain, type 482 #if defined(EPOLL_FOR_SOCKETS) 483 | SOCK_NONBLOCK 484 #endif 485 , protocol); 290 return socket(domain, type, protocol); 486 291 } 487 292 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) { … … 494 299 495 300 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) { 496 #if defined(EPOLL_FOR_SOCKETS) 497 int ret; 498 for() { 499 yield(); 500 ret = accept4(socket, address, address_len, SOCK_NONBLOCK); 501 if(ret >= 0) break; 502 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 503 504 epoll_wait(socket, EPOLLIN); 505 } 506 return ret; 507 #else 508 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY); 509 #endif 301 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY); 510 302 } 511 303 512 304 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) { 513 #if defined(EPOLL_FOR_SOCKETS) 514 int ret; 515 for() { 516 ret = connect(socket, address, address_len); 517 if(ret >= 0) break; 518 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 519 520 epoll_wait(socket, EPOLLIN); 521 } 522 return ret; 523 #else 524 return cfa_connect(socket, address, address_len, CFA_IO_LAZY); 525 #endif 305 return cfa_connect(socket, address, address_len, CFA_IO_LAZY); 526 306 } 527 307 … … 535 315 536 316 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) { 537 #if defined(EPOLL_FOR_SOCKETS) 538 ssize_t ret; 539 __STATS__( false, io.ops.sockwrite++; ) 540 for() { 541 ret = sendmsg(socket, message, flags); 542 if(ret >= 0) break; 543 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 544 545 __STATS__( false, io.ops.epllwrite++; ) 546 epoll_wait(socket, EPOLLOUT); 547 } 548 #else 549 ssize_t ret = cfa_sendmsg(socket, message, flags, CFA_IO_LAZY); 550 #endif 551 return ret; 317 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY); 552 318 } 553 319 554 320 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) { 555 321 // Use send rather then write for socket since it's faster 556 #if defined(EPOLL_FOR_SOCKETS) 557 ssize_t ret; 558 // __STATS__( false, io.ops.sockwrite++; ) 559 for() { 560 ret = send(fildes, buf, nbyte, 0); 561 if(ret >= 0) break; 562 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 563 564 // __STATS__( false, io.ops.epllwrite++; ) 565 epoll_wait(fildes, EPOLLOUT); 566 } 567 #else 568 ssize_t ret = cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY); 569 #endif 570 return ret; 322 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY); 571 323 } 572 324 … … 584 336 msg.msg_controllen = 0; 585 337 586 #if defined(EPOLL_FOR_SOCKETS) 587 ssize_t ret; 588 yield(); 589 for() { 590 ret = recvmsg(socket, &msg, flags); 591 if(ret >= 0) break; 592 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 593 594 epoll_wait(socket, EPOLLIN); 595 } 596 #else 597 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY); 598 #endif 338 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY); 599 339 600 340 if(address_len) *address_len = msg.msg_namelen; … … 604 344 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) { 605 345 // Use recv rather then read for socket since it's faster 606 #if defined(EPOLL_FOR_SOCKETS) 607 ssize_t ret; 608 __STATS__( false, io.ops.sockread++; ) 609 yield(); 610 for() { 611 ret = recv(fildes, buf, nbyte, 0); 612 if(ret >= 0) break; 613 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 614 615 __STATS__( false, io.ops.epllread++; ) 616 epoll_wait(fildes, EPOLLIN); 617 } 618 #else 619 ssize_t ret = cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY); 620 #endif 621 return ret; 622 } 623 624 } 346 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY); 347 } 348 349 } -
libcfa/src/concurrency/invoke.h
rf93c50a r7e7a076 170 170 bool corctx_flag; 171 171 172 int last_cpu; 173 172 174 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it 173 175 … … 175 177 struct cluster * curr_cluster; 176 178 177 // preferred ready-queue or CPU179 // preferred ready-queue 178 180 unsigned preferred; 179 181 -
libcfa/src/concurrency/io.cfa
rf93c50a r7e7a076 90 90 static inline unsigned __flush( struct $io_context & ); 91 91 static inline __u32 __release_sqes( struct $io_context & ); 92 extern void __kernel_unpark( thread$ * thrd , unpark_hint);92 extern void __kernel_unpark( thread$ * thrd ); 93 93 94 94 bool __cfa_io_drain( processor * proc ) { … … 118 118 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 119 119 120 __kernel_unpark( fulfil( *future, cqe.res, false ) , UNPARK_LOCAL);120 __kernel_unpark( fulfil( *future, cqe.res, false ) ); 121 121 } 122 122 -
libcfa/src/concurrency/kernel.cfa
rf93c50a r7e7a076 341 341 } 342 342 343 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )343 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 344 344 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 345 345 346 { 347 eventfd_t val; 348 ssize_t ret = read( this->idle, &val, sizeof(val) ); 349 if(ret < 0) { 350 switch((int)errno) { 351 case EAGAIN: 352 #if EAGAIN != EWOULDBLOCK 353 case EWOULDBLOCK: 354 #endif 355 case EINTR: 356 // No need to do anything special here, just assume it's a legitimate wake-up 357 break; 358 default: 359 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 360 } 361 } 362 } 346 // __disable_interrupts_hard(); 347 eventfd_t val; 348 eventfd_read( this->idle, &val ); 349 // __enable_interrupts_hard(); 363 350 364 351 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) … … 422 409 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 423 410 __builtin_prefetch( thrd_dst->context.SP ); 411 412 int curr = __kernel_getcpu(); 413 if(thrd_dst->last_cpu != curr) { 414 int64_t l = thrd_dst->last_cpu; 415 int64_t c = curr; 416 int64_t v = (l << 32) | c; 417 __push_stat( __tls_stats(), v, false, "Processor", this ); 418 } 419 420 thrd_dst->last_cpu = curr; 424 421 425 422 __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name); … … 476 473 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 477 474 // The thread was preempted, reschedule it and reset the flag 478 schedule_thread$( thrd_dst , UNPARK_LOCAL);475 schedule_thread$( thrd_dst ); 479 476 break RUNNING; 480 477 } … … 560 557 // Scheduler routines 561 558 // KERNEL ONLY 562 static void __schedule_thread( thread$ * thrd , unpark_hint hint) {559 static void __schedule_thread( thread$ * thrd ) { 563 560 /* paranoid */ verify( ! __preemption_enabled() ); 564 561 /* paranoid */ verify( ready_schedule_islocked()); … … 580 577 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 581 578 struct cluster * cl = thrd->curr_cluster; 582 __STATS(bool outside = hint == UNPARK_LOCAL &&thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )579 __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 583 580 584 581 // push the thread to the cluster ready-queue 585 push( cl, thrd, hint);582 push( cl, thrd, local ); 586 583 587 584 // variable thrd is no longer safe to use … … 608 605 } 609 606 610 void schedule_thread$( thread$ * thrd , unpark_hint hint) {607 void schedule_thread$( thread$ * thrd ) { 611 608 ready_schedule_lock(); 612 __schedule_thread( thrd , hint);609 __schedule_thread( thrd ); 613 610 ready_schedule_unlock(); 614 611 } … … 661 658 } 662 659 663 void __kernel_unpark( thread$ * thrd , unpark_hint hint) {660 void __kernel_unpark( thread$ * thrd ) { 664 661 /* paranoid */ verify( ! __preemption_enabled() ); 665 662 /* paranoid */ verify( ready_schedule_islocked()); … … 669 666 if(__must_unpark(thrd)) { 670 667 // Wake lost the race, 671 __schedule_thread( thrd , hint);668 __schedule_thread( thrd ); 672 669 } 673 670 … … 676 673 } 677 674 678 void unpark( thread$ * thrd , unpark_hint hint) {675 void unpark( thread$ * thrd ) { 679 676 if( !thrd ) return; 680 677 … … 682 679 disable_interrupts(); 683 680 // Wake lost the race, 684 schedule_thread$( thrd , hint);681 schedule_thread$( thrd ); 685 682 enable_interrupts(false); 686 683 } -
libcfa/src/concurrency/kernel.hfa
rf93c50a r7e7a076 151 151 struct __attribute__((aligned(128))) __timestamp_t { 152 152 volatile unsigned long long tv; 153 volatile unsigned long long ma; 154 }; 155 156 // Aligned timestamps which are used by the relaxed ready queue 157 struct __attribute__((aligned(128))) __help_cnts_t { 158 volatile unsigned long long src; 159 volatile unsigned long long dst; 160 volatile unsigned long long tri; 161 }; 162 163 static inline void ?{}(__timestamp_t & this) { this.tv = 0; this.ma = 0; } 153 }; 154 155 static inline void ?{}(__timestamp_t & this) { this.tv = 0; } 164 156 static inline void ^?{}(__timestamp_t & this) {} 165 157 … … 177 169 // Array of times 178 170 __timestamp_t * volatile tscs; 179 180 // Array of stats181 __help_cnts_t * volatile help;182 171 183 172 // Number of lanes (empty or not) -
libcfa/src/concurrency/kernel/fwd.hfa
rf93c50a r7e7a076 119 119 120 120 extern "Cforall" { 121 enum unpark_hint { UNPARK_LOCAL, UNPARK_REMOTE };122 123 121 extern void park( void ); 124 extern void unpark( struct thread$ *, unpark_hint ); 125 static inline void unpark( struct thread$ * thrd ) { unpark(thrd, UNPARK_LOCAL); } 122 extern void unpark( struct thread$ * this ); 126 123 static inline struct thread$ * active_thread () { 127 124 struct thread$ * t = publicTLS_get( this_thread ); -
libcfa/src/concurrency/kernel/startup.cfa
rf93c50a r7e7a076 200 200 __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n"); 201 201 202 // Construct the processor context of the main processor203 void ?{}(processorCtx_t & this, processor * proc) {204 (this.__cor){ "Processor" };205 this.__cor.starter = 0p;206 this.proc = proc;207 }208 209 void ?{}(processor & this) with( this ) {210 ( this.terminated ){};211 ( this.runner ){};212 init( this, "Main Processor", *mainCluster, 0p );213 kernel_thread = pthread_self();214 215 runner{ &this };216 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);217 }218 219 // Initialize the main processor and the main processor ctx220 // (the coroutine that contains the processing control flow)221 mainProcessor = (processor *)&storage_mainProcessor;222 (*mainProcessor){};223 224 register_tls( mainProcessor );225 226 202 // Start by initializing the main thread 227 203 // SKULLDUGGERY: the mainThread steals the process main thread … … 234 210 __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n"); 235 211 212 213 214 // Construct the processor context of the main processor 215 void ?{}(processorCtx_t & this, processor * proc) { 216 (this.__cor){ "Processor" }; 217 this.__cor.starter = 0p; 218 this.proc = proc; 219 } 220 221 void ?{}(processor & this) with( this ) { 222 ( this.terminated ){}; 223 ( this.runner ){}; 224 init( this, "Main Processor", *mainCluster, 0p ); 225 kernel_thread = pthread_self(); 226 227 runner{ &this }; 228 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner); 229 } 230 231 // Initialize the main processor and the main processor ctx 232 // (the coroutine that contains the processing control flow) 233 mainProcessor = (processor *)&storage_mainProcessor; 234 (*mainProcessor){}; 235 236 register_tls( mainProcessor ); 237 mainThread->last_cpu = __kernel_getcpu(); 238 236 239 //initialize the global state variables 237 240 __cfaabi_tls.this_processor = mainProcessor; … … 249 252 // Add the main thread to the ready queue 250 253 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 251 schedule_thread$(mainThread , UNPARK_LOCAL);254 schedule_thread$(mainThread); 252 255 253 256 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 483 486 link.next = 0p; 484 487 link.ts = -1llu; 485 preferred = ready_queue_new_preferred();488 preferred = -1u; 486 489 last_proc = 0p; 487 490 #if defined( __CFA_WITH_VERIFY__ ) -
libcfa/src/concurrency/kernel_private.hfa
rf93c50a r7e7a076 46 46 } 47 47 48 void schedule_thread$( thread$ * , unpark_hint hint) __attribute__((nonnull (1)));48 void schedule_thread$( thread$ * ) __attribute__((nonnull (1))); 49 49 50 50 extern bool __preemption_enabled(); … … 300 300 // push thread onto a ready queue for a cluster 301 301 // returns true if the list was previously empty, false otherwise 302 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint);302 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool local); 303 303 304 304 //----------------------------------------------------------------------- … … 321 321 322 322 //----------------------------------------------------------------------- 323 // get preferred ready for new thread324 unsigned ready_queue_new_preferred();325 326 //-----------------------------------------------------------------------327 323 // Increase the width of the ready queue (number of lanes) by 4 328 324 void ready_queue_grow (struct cluster * cltr); -
libcfa/src/concurrency/ready_queue.cfa
rf93c50a r7e7a076 100 100 #define __kernel_rseq_unregister rseq_unregister_current_thread 101 101 #elif defined(CFA_HAVE_LINUX_RSEQ_H) 102 staticvoid __kernel_raw_rseq_register (void);103 staticvoid __kernel_raw_rseq_unregister(void);102 void __kernel_raw_rseq_register (void); 103 void __kernel_raw_rseq_unregister(void); 104 104 105 105 #define __kernel_rseq_register __kernel_raw_rseq_register … … 246 246 // Cforall Ready Queue used for scheduling 247 247 //======================================================================= 248 unsigned long long moving_average(unsigned long long nval, unsigned long long oval) {249 const unsigned long long tw = 16;250 const unsigned long long nw = 4;251 const unsigned long long ow = tw - nw;252 return ((nw * nval) + (ow * oval)) / tw;253 }254 255 248 void ?{}(__ready_queue_t & this) with (this) { 256 249 #if defined(USE_CPU_WORK_STEALING) … … 258 251 lanes.data = alloc( lanes.count ); 259 252 lanes.tscs = alloc( lanes.count ); 260 lanes.help = alloc( cpu_info.hthrd_count );261 253 262 254 for( idx; (size_t)lanes.count ) { 263 255 (lanes.data[idx]){}; 264 256 lanes.tscs[idx].tv = rdtscl(); 265 lanes.tscs[idx].ma = rdtscl();266 }267 for( idx; (size_t)cpu_info.hthrd_count ) {268 lanes.help[idx].src = 0;269 lanes.help[idx].dst = 0;270 lanes.help[idx].tri = 0;271 257 } 272 258 #else 273 259 lanes.data = 0p; 274 260 lanes.tscs = 0p; 275 lanes.help = 0p;276 261 lanes.count = 0; 277 262 #endif … … 285 270 free(lanes.data); 286 271 free(lanes.tscs); 287 free(lanes.help);288 272 } 289 273 290 274 //----------------------------------------------------------------------- 291 275 #if defined(USE_CPU_WORK_STEALING) 292 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {276 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 293 277 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 294 278 295 279 processor * const proc = kernelTLS().this_processor; 296 const bool external = (!proc) || (cltr != proc->cltr); 297 298 // Figure out the current cpu and make sure it is valid 280 const bool external = !push_local || (!proc) || (cltr != proc->cltr); 281 299 282 const int cpu = __kernel_getcpu(); 300 283 /* paranoid */ verify(cpu >= 0); … … 302 285 /* paranoid */ verify(cpu * READYQ_SHARD_FACTOR < lanes.count); 303 286 304 // Figure out where thread was last time and make sure it's 305 /* paranoid */ verify(thrd->preferred >= 0); 306 /* paranoid */ verify(thrd->preferred < cpu_info.hthrd_count); 307 /* paranoid */ verify(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count); 308 const int prf = thrd->preferred * READYQ_SHARD_FACTOR; 309 310 const cpu_map_entry_t & map; 311 choose(hint) { 312 case UNPARK_LOCAL : &map = &cpu_info.llc_map[cpu]; 313 case UNPARK_REMOTE: &map = &cpu_info.llc_map[prf]; 314 } 287 const cpu_map_entry_t & map = cpu_info.llc_map[cpu]; 315 288 /* paranoid */ verify(map.start * READYQ_SHARD_FACTOR < lanes.count); 316 289 /* paranoid */ verify(map.self * READYQ_SHARD_FACTOR < lanes.count); … … 323 296 if(unlikely(external)) { r = __tls_rand(); } 324 297 else { r = proc->rdq.its++; } 325 choose(hint) { 326 case UNPARK_LOCAL : i = start + (r % READYQ_SHARD_FACTOR); 327 case UNPARK_REMOTE: i = prf + (r % READYQ_SHARD_FACTOR); 328 } 298 i = start + (r % READYQ_SHARD_FACTOR); 329 299 // If we can't lock it retry 330 300 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); … … 362 332 processor * const proc = kernelTLS().this_processor; 363 333 const int start = map.self * READYQ_SHARD_FACTOR; 364 const unsigned long long ctsc = rdtscl();365 334 366 335 // Did we already have a help target 367 336 if(proc->rdq.target == -1u) { 368 unsigned long long max = 0; 337 // if We don't have a 338 unsigned long long min = ts(lanes.data[start]); 369 339 for(i; READYQ_SHARD_FACTOR) { 370 unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma); 371 if(tsc > max) max = tsc; 372 } 373 proc->rdq.cutoff = (max + 2 * max) / 2; 340 unsigned long long tsc = ts(lanes.data[start + i]); 341 if(tsc < min) min = tsc; 342 } 343 proc->rdq.cutoff = min; 344 374 345 /* paranoid */ verify(lanes.count < 65536); // The following code assumes max 65536 cores. 375 346 /* paranoid */ verify(map.count < 65536); // The following code assumes max 65536 cores. 376 347 377 if(0 == (__tls_rand() % 10 0)) {348 if(0 == (__tls_rand() % 10_000)) { 378 349 proc->rdq.target = __tls_rand() % lanes.count; 379 350 } else { … … 387 358 } 388 359 else { 389 unsigned long long max = 0; 390 for(i; READYQ_SHARD_FACTOR) { 391 unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma); 392 if(tsc > max) max = tsc; 393 } 394 const unsigned long long cutoff = (max + 2 * max) / 2; 360 const unsigned long long bias = 0; //2_500_000_000; 361 const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff; 395 362 { 396 363 unsigned target = proc->rdq.target; 397 364 proc->rdq.target = -1u; 398 lanes.help[target / READYQ_SHARD_FACTOR].tri++; 399 if(moving_average(ctsc - lanes.tscs[target].tv, lanes.tscs[target].ma) > cutoff) { 365 if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) { 400 366 thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help)); 401 367 proc->rdq.last = target; 402 368 if(t) return t; 403 else proc->rdq.target = -1u;404 369 } 405 else proc->rdq.target = -1u;406 370 } 407 371 … … 464 428 } 465 429 466 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {430 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 467 431 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 468 432 469 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);433 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 470 434 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 471 435 … … 551 515 #endif 552 516 #if defined(USE_WORK_STEALING) 553 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {517 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 554 518 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 555 519 556 520 // #define USE_PREFERRED 557 521 #if !defined(USE_PREFERRED) 558 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);522 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 559 523 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 560 524 #else 561 525 unsigned preferred = thrd->preferred; 562 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;526 const bool external = push_local || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr; 563 527 /* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count ); 564 528 … … 681 645 // Actually pop the list 682 646 struct thread$ * thrd; 683 unsigned long long tsc_before = ts(lane);684 647 unsigned long long tsv; 685 648 [thrd, tsv] = pop(lane); … … 695 658 __STATS( stats.success++; ) 696 659 697 #if defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING) 698 unsigned long long now = rdtscl(); 660 #if defined(USE_WORK_STEALING) 699 661 lanes.tscs[w].tv = tsv; 700 lanes.tscs[w].ma = moving_average(now > tsc_before ? now - tsc_before : 0, lanes.tscs[w].ma);701 662 #endif 702 663 703 #if defined(USE_CPU_WORK_STEALING) 704 thrd->preferred = w / READYQ_SHARD_FACTOR; 705 #else 706 thrd->preferred = w; 707 #endif 664 thrd->preferred = w; 708 665 709 666 // return the popped thread … … 731 688 732 689 //----------------------------------------------------------------------- 733 // get preferred ready for new thread734 unsigned ready_queue_new_preferred() {735 unsigned pref = 0;736 if(struct thread$ * thrd = publicTLS_get( this_thread )) {737 pref = thrd->preferred;738 }739 else {740 #if defined(USE_CPU_WORK_STEALING)741 pref = __kernel_getcpu();742 #endif743 }744 745 #if defined(USE_CPU_WORK_STEALING)746 /* paranoid */ verify(pref >= 0);747 /* paranoid */ verify(pref < cpu_info.hthrd_count);748 #endif749 750 return pref;751 }752 753 //-----------------------------------------------------------------------754 690 // Check that all the intrusive queues in the data structure are still consistent 755 691 static void check( __ready_queue_t & q ) with (q) { … … 979 915 extern void __enable_interrupts_hard(); 980 916 981 staticvoid __kernel_raw_rseq_register (void) {917 void __kernel_raw_rseq_register (void) { 982 918 /* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED ); 983 919 … … 997 933 } 998 934 999 staticvoid __kernel_raw_rseq_unregister(void) {935 void __kernel_raw_rseq_unregister(void) { 1000 936 /* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 ); 1001 937 -
libcfa/src/concurrency/ready_subqueue.hfa
rf93c50a r7e7a076 98 98 99 99 // Get the relevant nodes locally 100 unsigned long long ts = this.anchor.ts; 100 101 thread$ * node = this.anchor.next; 101 102 this.anchor.next = node->link.next; … … 115 116 /* paranoid */ verify( node->link.ts != 0 ); 116 117 /* paranoid */ verify( this.anchor.ts != 0 ); 117 return [node, t his.anchor.ts];118 return [node, ts]; 118 119 } 119 120 -
libcfa/src/concurrency/stats.cfa
rf93c50a r7e7a076 48 48 stats->io.calls.completed = 0; 49 49 stats->io.calls.errors.busy = 0; 50 stats->io.ops.sockread = 0;51 stats->io.ops.epllread = 0;52 stats->io.ops.sockwrite = 0;53 stats->io.ops.epllwrite = 0;54 50 #endif 55 51 … … 108 104 tally_one( &cltr->io.calls.completed , &proc->io.calls.completed ); 109 105 tally_one( &cltr->io.calls.errors.busy, &proc->io.calls.errors.busy ); 110 tally_one( &cltr->io.ops.sockread , &proc->io.ops.sockread );111 tally_one( &cltr->io.ops.epllread , &proc->io.ops.epllread );112 tally_one( &cltr->io.ops.sockwrite , &proc->io.ops.sockwrite );113 tally_one( &cltr->io.ops.epllwrite , &proc->io.ops.epllwrite );114 106 #endif 115 107 } … … 187 179 | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)" 188 180 | " - " | eng3(io.calls.errors.busy) | " EBUSY"; 189 sstr | "- ops blk: "190 | " sk rd: " | eng3(io.ops.sockread) | "epll: " | eng3(io.ops.epllread)191 | " sk wr: " | eng3(io.ops.sockwrite) | "epll: " | eng3(io.ops.epllwrite);192 181 sstr | nl; 193 182 } -
libcfa/src/concurrency/stats.hfa
rf93c50a r7e7a076 102 102 volatile uint64_t sleeps; 103 103 } poller; 104 struct {105 volatile uint64_t sockread;106 volatile uint64_t epllread;107 volatile uint64_t sockwrite;108 volatile uint64_t epllwrite;109 } ops;110 104 }; 111 105 #endif -
libcfa/src/concurrency/thread.cfa
rf93c50a r7e7a076 25 25 #include "invoke.h" 26 26 27 uint64_t thread_rand();28 29 27 //----------------------------------------------------------------------------- 30 28 // Thread ctors and dtors … … 36 34 preempted = __NO_PREEMPTION; 37 35 corctx_flag = false; 36 disable_interrupts(); 37 last_cpu = __kernel_getcpu(); 38 enable_interrupts(); 38 39 curr_cor = &self_cor; 39 40 self_mon.owner = &this; … … 43 44 link.next = 0p; 44 45 link.ts = -1llu; 45 preferred = ready_queue_new_preferred();46 preferred = -1u; 46 47 last_proc = 0p; 47 48 #if defined( __CFA_WITH_VERIFY__ ) … … 140 141 /* paranoid */ verify( this_thrd->context.SP ); 141 142 142 schedule_thread$( this_thrd , UNPARK_LOCAL);143 schedule_thread$( this_thrd ); 143 144 enable_interrupts(); 144 145 } -
libcfa/src/containers/string_res.cfa
rf93c50a r7e7a076 21 21 22 22 23 24 25 26 27 28 29 // DON'T COMMIT: 30 // #define VbyteDebug 31 32 33 34 35 36 #ifdef VbyteDebug 37 HandleNode *HeaderPtr; 23 #ifdef VbyteDebug 24 extern HandleNode *HeaderPtr; 38 25 #endif // VbyteDebug 39 26 … … 153 140 154 141 VbyteHeap HeapArea; 155 156 VbyteHeap * DEBUG_string_heap = & HeapArea;157 158 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {159 return ((char*)heap->ExtVbyte) - heap->EndVbyte;160 }161 162 const char * DEBUG_string_heap_start( VbyteHeap * heap ) {163 return heap->StartVbyte;164 }165 166 142 167 143 // Returns the size of the string in bytes … … 249 225 void assign(string_res &this, const char* buffer, size_t bsize) { 250 226 251 // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs 252 string_res * shareEditSetStartPeer = & this; 253 string_res * shareEditSetEndPeer = & this; 227 char * afterBegin = this.Handle.s + this.Handle.lnth; 228 229 char * shareEditSetStart = this.Handle.s; 230 char * shareEditSetEnd = afterBegin; 254 231 for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) { 255 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 256 shareEditSetStartPeer = editPeer; 257 } 258 if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) { 259 shareEditSetEndPeer = editPeer; 260 } 261 } 262 263 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 264 // `this` occurs in the middle of it, to be replaced 265 // build up the new text in `pasting` 266 267 string_res pasting = { 268 shareEditSetStartPeer->Handle.s, // start of SES 269 this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this 270 append( pasting, 271 buffer, // start of replacement for this 272 bsize ); // length of replacement for this 273 append( pasting, 274 this.Handle.s + this.Handle.lnth, // start of SES after this 275 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 276 (this.Handle.s + this.Handle.lnth) ); // length of SES, after this 277 278 // The above string building can trigger compaction. 279 // The reference points (that are arguments of the string building) may move during that building. 280 // From this point on, they are stable. 281 // So now, capture their values for use in the overlap cases, below. 282 // Do not factor these definitions with the arguments used above. 283 284 char * beforeBegin = shareEditSetStartPeer->Handle.s; 285 size_t beforeLen = this.Handle.s - beforeBegin; 286 287 char * afterBegin = this.Handle.s + this.Handle.lnth; 288 size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin; 232 shareEditSetStart = min( shareEditSetStart, editPeer->Handle.s ); 233 shareEditSetEnd = max( shareEditSetStart, editPeer->Handle.s + editPeer->Handle.lnth); 234 } 235 236 char * beforeBegin = shareEditSetStart; 237 size_t beforeLen = this.Handle.s - shareEditSetStart; 238 size_t afterLen = shareEditSetEnd - afterBegin; 239 240 string_res pasting = { beforeBegin, beforeLen }; 241 append(pasting, buffer, bsize); 242 string_res after = { afterBegin, afterLen }; // juxtaposed with in-progress pasting 243 pasting += after; // optimized case 289 244 290 245 size_t oldLnth = this.Handle.lnth; … … 298 253 for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) { 299 254 assert (p->Handle.s >= beforeBegin); 300 if ( p->Handle.s >= afterBegin ) { 301 assert ( p->Handle.s <= afterBegin + afterLen ); 302 assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 303 // p starts after the edit 304 // take start and end as end-anchored 305 size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s; 306 p->Handle.s = limit - startOffsetFromEnd; 307 // p->Handle.lnth unaffected 308 } else if ( p->Handle.s <= beforeBegin + beforeLen ) { 309 // p starts before, or at the start of, the edit 310 if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) { 255 if ( p->Handle.s < beforeBegin + beforeLen ) { 256 // p starts before the edit 257 if ( p->Handle.s + p->Handle.lnth < beforeBegin + beforeLen ) { 311 258 // p ends before the edit 312 259 // take end as start-anchored too 313 260 // p->Handle.lnth unaffected 314 261 } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 315 // p ends during the edit ; p does not include the last character replaced262 // p ends during the edit 316 263 // clip end of p to end at start of edit 317 264 p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin ); … … 327 274 size_t startOffsetFromStart = p->Handle.s - beforeBegin; 328 275 p->Handle.s = pasting.Handle.s + startOffsetFromStart; 329 } else { 330 assert ( p->Handle.s < afterBegin ); 276 } else if ( p->Handle.s < afterBegin ) { 331 277 // p starts during the edit 332 278 assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen ); 333 279 if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 334 // p ends during the edit ; p does not include the last character replaced280 // p ends during the edit 335 281 // set p to empty string at start of edit 336 282 p->Handle.s = this.Handle.s; 337 283 p->Handle.lnth = 0; 338 284 } else { 339 // p includes the end ofthe edit285 // p ends after the edit 340 286 // clip start of p to start at end of edit 341 int charsToClip = afterBegin - p->Handle.s;342 287 p->Handle.s = this.Handle.s + this.Handle.lnth; 343 p->Handle.lnth -= charsToClip; 288 p->Handle.lnth += this.Handle.lnth; 289 p->Handle.lnth -= oldLnth; 344 290 } 291 } else { 292 assert ( p->Handle.s <= afterBegin + afterLen ); 293 assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 294 // p starts after the edit 295 // take start and end as end-anchored 296 size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s; 297 p->Handle.s = limit - startOffsetFromEnd; 298 // p->Handle.lnth unaffected 345 299 } 346 300 MoveThisAfter( p->Handle, pasting.Handle ); // move substring handle to maintain sorted order by string position … … 687 641 } // if 688 642 #ifdef VbyteDebug 643 serr | "exit:MoveThisAfter"; 689 644 { 690 645 serr | "HandleList:"; … … 695 650 serr | n->s[i]; 696 651 } // for 697 serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;652 serr | "\" flink:" | n->flink | " blink:" | n->blink; 698 653 } // for 699 654 serr | nlOn; 700 655 } 701 serr | "exit:MoveThisAfter";702 656 #endif // VbyteDebug 703 657 } // MoveThisAfter … … 708 662 709 663 //######################### VbyteHeap ######################### 664 665 #ifdef VbyteDebug 666 HandleNode *HeaderPtr = 0p; 667 #endif // VbyteDebug 710 668 711 669 // Move characters from one location in the byte-string area to another. The routine handles the following situations: -
libcfa/src/containers/string_res.hfa
rf93c50a r7e7a076 36 36 void ?{}( HandleNode &, VbyteHeap & ); // constructor for nodes in the handle list 37 37 void ^?{}( HandleNode & ); // destructor for handle nodes 38 39 extern VbyteHeap * DEBUG_string_heap;40 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap );41 const char * DEBUG_string_heap_start( VbyteHeap * heap );42 38 43 39 -
libcfa/src/fstream.cfa
rf93c50a r7e7a076 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Sep 21 21:51:38202113 // Update Count : 4 6012 // Last Modified On : Thu Jul 29 22:34:10 2021 13 // Update Count : 454 14 14 // 15 15 … … 28 28 #define IO_MSG "I/O error: " 29 29 30 void ?{}( ofstream & os, void * file ) with(os){31 file$ = file;32 sepDefault$ = true;33 sepOnOff$ = false;34 nlOnOff$ = true;35 prt$ = false;36 sawNL$ = false;37 acquired$ = false;30 void ?{}( ofstream & os, void * file ) { 31 os.file$ = file; 32 os.sepDefault$ = true; 33 os.sepOnOff$ = false; 34 os.nlOnOff$ = true; 35 os.prt$ = false; 36 os.sawNL$ = false; 37 os.acquired$ = false; 38 38 sepSetCur$( os, sepGet( os ) ); 39 39 sepSet( os, " " ); … … 124 124 void open( ofstream & os, const char name[], const char mode[] ) { 125 125 FILE * file = fopen( name, mode ); 126 // #ifdef __CFA_DEBUG__ 126 127 if ( file == 0p ) { 127 128 throw (Open_Failure){ os }; 128 129 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 129 130 } // if 130 (os){ file }; // initialize 131 // #endif // __CFA_DEBUG__ 132 (os){ file }; 131 133 } // open 132 134 … … 135 137 } // open 136 138 137 void close( ofstream & os ) with(os){138 if ( (FILE *)( file$) == 0p ) return;139 if ( (FILE *)( file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;140 141 if ( fclose( (FILE *)( file$) ) == EOF ) {139 void close( ofstream & os ) { 140 if ( (FILE *)(os.file$) == 0p ) return; 141 if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return; 142 143 if ( fclose( (FILE *)(os.file$) ) == EOF ) { 142 144 throw (Close_Failure){ os }; 143 145 // abort | IO_MSG "close output" | nl | strerror( errno ); 144 146 } // if 145 file$ = 0p;147 os.file$ = 0p; 146 148 } // close 147 149 … … 175 177 } // fmt 176 178 177 inline void acquire( ofstream & os ) with(os){178 lock( lock$ ); // may increase recursive lock179 if ( ! acquired$ ) acquired$ = true; // not locked ?180 else unlock( lock$ ); // unwind recursive lock at start179 inline void acquire( ofstream & os ) { 180 lock( os.lock$ ); 181 if ( ! os.acquired$ ) os.acquired$ = true; 182 else unlock( os.lock$ ); 181 183 } // acquire 182 184 … … 185 187 } // release 186 188 187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; } 189 inline void lock( ofstream & os ) { acquire( os ); } 190 inline void unlock( ofstream & os ) { release( os ); } 191 192 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); } 188 193 void ^?{}( osacquire & acq ) { release( acq.os ); } 189 194 … … 217 222 218 223 // private 219 void ?{}( ifstream & is, void * file ) with(is){220 file$ = file;221 nlOnOff$ = false;222 acquired$ = false;224 void ?{}( ifstream & is, void * file ) { 225 is.file$ = file; 226 is.nlOnOff$ = false; 227 is.acquired$ = false; 223 228 } // ?{} 224 229 … … 260 265 void open( ifstream & is, const char name[], const char mode[] ) { 261 266 FILE * file = fopen( name, mode ); 267 // #ifdef __CFA_DEBUG__ 262 268 if ( file == 0p ) { 263 269 throw (Open_Failure){ is }; 264 270 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 265 271 } // if 266 (is){ file }; // initialize 272 // #endif // __CFA_DEBUG__ 273 is.file$ = file; 267 274 } // open 268 275 … … 271 278 } // open 272 279 273 void close( ifstream & is ) with(is){274 if ( (FILE *)( file$) == 0p ) return;275 if ( (FILE *)( file$) == (FILE *)stdin ) return;276 277 if ( fclose( (FILE *)( file$) ) == EOF ) {280 void close( ifstream & is ) { 281 if ( (FILE *)(is.file$) == 0p ) return; 282 if ( (FILE *)(is.file$) == (FILE *)stdin ) return; 283 284 if ( fclose( (FILE *)(is.file$) ) == EOF ) { 278 285 throw (Close_Failure){ is }; 279 286 // abort | IO_MSG "close input" | nl | strerror( errno ); 280 287 } // if 281 file$ = 0p;288 is.file$ = 0p; 282 289 } // close 283 290 … … 320 327 } // fmt 321 328 322 inline void acquire( ifstream & is ) with(is){323 lock( lock$ ); // may increase recursive lock324 if ( ! acquired$ ) acquired$ = true; // not locked ?325 else unlock( lock$ ); // unwind recursive lock at start329 inline void acquire( ifstream & is ) { 330 lock( is.lock$ ); 331 if ( ! is.acquired$ ) is.acquired$ = true; 332 else unlock( is.lock$ ); 326 333 } // acquire 327 334 … … 330 337 } // release 331 338 332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }339 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); } 333 340 void ^?{}( isacquire & acq ) { release( acq.is ); } 334 341 … … 343 350 344 351 // exception I/O constructors 345 void ?{}( Open_Failure & ex, ofstream & ostream ) with(ex) {346 virtual_table = &Open_Failure_vt;347 ostream = &ostream;348 t ag = 1;349 } // ?{} 350 351 void ?{}( Open_Failure & ex, ifstream & istream ) with(ex) {352 virtual_table = &Open_Failure_vt;353 istream = &istream;354 t ag = 0;352 void ?{}( Open_Failure & this, ofstream & ostream ) { 353 this.virtual_table = &Open_Failure_vt; 354 this.ostream = &ostream; 355 this.tag = 1; 356 } // ?{} 357 358 void ?{}( Open_Failure & this, ifstream & istream ) { 359 this.virtual_table = &Open_Failure_vt; 360 this.istream = &istream; 361 this.tag = 0; 355 362 } // ?{} 356 363 … … 359 366 360 367 // exception I/O constructors 361 void ?{}( Close_Failure & ex, ofstream & ostream ) with(ex) {362 virtual_table = &Close_Failure_vt;363 ostream = &ostream;364 t ag = 1;365 } // ?{} 366 367 void ?{}( Close_Failure & ex, ifstream & istream ) with(ex) {368 virtual_table = &Close_Failure_vt;369 istream = &istream;370 t ag = 0;368 void ?{}( Close_Failure & this, ofstream & ostream ) { 369 this.virtual_table = &Close_Failure_vt; 370 this.ostream = &ostream; 371 this.tag = 1; 372 } // ?{} 373 374 void ?{}( Close_Failure & this, ifstream & istream ) { 375 this.virtual_table = &Close_Failure_vt; 376 this.istream = &istream; 377 this.tag = 0; 371 378 } // ?{} 372 379 … … 375 382 376 383 // exception I/O constructors 377 void ?{}( Write_Failure & ex, ofstream & ostream ) with(ex) {378 virtual_table = &Write_Failure_vt;379 ostream = &ostream;380 t ag = 1;381 } // ?{} 382 383 void ?{}( Write_Failure & ex, ifstream & istream ) with(ex) {384 virtual_table = &Write_Failure_vt;385 istream = &istream;386 t ag = 0;384 void ?{}( Write_Failure & this, ofstream & ostream ) { 385 this.virtual_table = &Write_Failure_vt; 386 this.ostream = &ostream; 387 this.tag = 1; 388 } // ?{} 389 390 void ?{}( Write_Failure & this, ifstream & istream ) { 391 this.virtual_table = &Write_Failure_vt; 392 this.istream = &istream; 393 this.tag = 0; 387 394 } // ?{} 388 395 … … 391 398 392 399 // exception I/O constructors 393 void ?{}( Read_Failure & ex, ofstream & ostream ) with(ex) {394 virtual_table = &Read_Failure_vt;395 ostream = &ostream;396 t ag = 1;397 } // ?{} 398 399 void ?{}( Read_Failure & ex, ifstream & istream ) with(ex) {400 virtual_table = &Read_Failure_vt;401 istream = &istream;402 t ag = 0;400 void ?{}( Read_Failure & this, ofstream & ostream ) { 401 this.virtual_table = &Read_Failure_vt; 402 this.ostream = &ostream; 403 this.tag = 1; 404 } // ?{} 405 406 void ?{}( Read_Failure & this, ifstream & istream ) { 407 this.virtual_table = &Read_Failure_vt; 408 this.istream = &istream; 409 this.tag = 0; 403 410 } // ?{} 404 411 -
tools/perf/process_stat_array.py
rf93c50a r7e7a076 1 1 #!/usr/bin/python3 2 2 3 import argparse, json, math, os, sys, re 4 from PIL import Image 5 import numpy as np 3 import argparse, os, sys, re 6 4 7 5 def dir_path(string): … … 13 11 parser = argparse.ArgumentParser() 14 12 parser.add_argument('--path', type=dir_path, default=".cfadata", help= 'paste path to biog.txt file') 15 parser.add_argument('--out', type=argparse.FileType('w'), default=sys.stdout)16 13 17 14 try : … … 26 23 counters = {} 27 24 28 max_cpu = 029 min_cpu = 100000030 max_tsc = 031 min_tsc = 1844674407370955161532 33 25 #open the files 34 26 for filename in filenames: … … 39 31 with open(os.path.join(root, filename), 'r') as file: 40 32 for line in file: 41 raw = [int(x.strip()) for x in line.split(',')] 42 43 ## from/to 44 high = (raw[1] >> 32) 45 low = (raw[1] & 0xffffffff) 46 data = [me, raw[0], high, low] 47 max_cpu = max(max_cpu, high, low) 48 min_cpu = min(min_cpu, high, low) 49 50 ## number 51 # high = (raw[1] >> 8) 52 # low = (raw[1] & 0xff) 53 # data = [me, raw[0], high, low] 54 # max_cpu = max(max_cpu, low) 55 # min_cpu = min(min_cpu, low) 56 57 58 max_tsc = max(max_tsc, raw[0]) 59 min_tsc = min(min_tsc, raw[0]) 33 # data = [int(x.strip()) for x in line.split(',')] 34 data = [int(line.strip())] 35 data = [me, *data] 60 36 merged.append(data) 61 37 62 except Exception as e: 63 print(e) 38 except: 64 39 pass 65 40 66 67 print({"max-cpu": max_cpu, "min-cpu": min_cpu, "max-tsc": max_tsc, "min-tsc": min_tsc})68 41 69 42 # Sort by timestamp (the second element) … … 74 47 merged.sort(key=takeSecond) 75 48 76 json.dump({"values":merged, "max-cpu": max_cpu, "min-cpu": min_cpu, "max-tsc": max_tsc, "min-tsc": min_tsc}, args.out) 49 # for m in merged: 50 # print(m) 77 51 78 # vmin = merged[ 0][1] 79 # vmax = float(merged[-1][1] - vmin) / 2500000000.0 80 # # print(vmax) 52 single = [] 53 curr = 0 81 54 82 # bins = [] 83 # for _ in range(0, int(math.ceil(vmax * 10))): 84 # bins.append([0] * (32 * 32)) 55 # merge the data 56 # for (me, time, value) in merged: 57 for (me, value) in merged: 58 # check now much this changes 59 old = counters[me] 60 change = value - old 61 counters[me] = value 85 62 86 # # print(len(bins)) 87 # bins = np.array(bins) 63 # add change to the current 64 curr = curr + change 65 single.append( value ) 88 66 89 # rejected = 0 90 # highest = 0 67 pass 91 68 92 # for x in merged: 93 # b = int(float(x[1] - vmin) / 250000000.0) 94 # from_ = x[2] 95 # if from_ < 0 or from_ > 32: 96 # rejected += 1 97 # continue; 98 # to_ = x[3] 99 # if to_ < 0 or to_ > 32: 100 # rejected += 1 101 # continue; 102 # idx = (to_ * 32) + from_ 103 # bins[b][idx] = bins[b][idx] + 1 104 # highest = max(highest, bins[b][idx]) 105 106 # bins = np.array(map(lambda x: np.int8(x * 255.0 / float(highest)), bins)) 107 108 # print([highest, rejected]) 109 # print(bins.shape) 110 111 # im = Image.fromarray(bins) 112 # im.save('test.png') 113 114 # vmax = merged[-1][1] 115 116 # diff = float(vmax - vmin) / 2500000000.0 117 # print([vmin, vmax]) 118 # print([vmax - vmin, diff]) 119 120 # print(len(merged)) 121 122 # for b in bins: 123 # print(b) 124 125 # single = [] 126 # curr = 0 127 128 # # merge the data 129 # # for (me, time, value) in merged: 130 # for (me, value) in merged: 131 # # check now much this changes 132 # old = counters[me] 133 # change = value - old 134 # counters[me] = value 135 136 # # add change to the current 137 # curr = curr + change 138 # single.append( value ) 139 140 # pass 141 142 # print(single) 69 print(single) 143 70 144 71 # single = sorted(single)[:len(single)-100]
Note:
See TracChangeset
for help on using the changeset viewer.